Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
4

Spawn() function - What is it? What is it used for? In what ways is it different than coroutines?

Asked by
Perci1 4988 Trusted Moderation Voter Community Moderator
9 years ago

I'm rather confused. Looking at the wiki documentation of spawn(), many things confuse me;

Spawn

spawn (f) or Spawn (f)

Executes function f after thread next yields.

Wait, what does that mean? What is the definition of 'next thread'? How/when will it yield? I assume they don't mean the kind of thread hanging off my sock?

An alternative to this is coroutines. Spawned functions and coroutines aren't used in the same way. Spawn is used to delay the execution of a functions until the thread yields while coroutines are used to run code immediately on a separate thread.

Still don't know what they mean by all that.

On the corountine manipulation page, the wiki says;

Note: ROBLOX also provides a function to create threads that may be used in replace of coroutines if creating a new thread is the only goal.

. . . Yet the other wiki page just said they're different.

So what exactly is the Spawn() function, what is it used for, and how is it different than corountines?

1 answer

Log in to vote
10
Answered by
Unclear 1776 Moderation Voter
9 years ago

A thread is a group of computer instructions that can be executed by a task scheduler, in particular Lua's thread task scheduler. In simple words, it is a block of code that runs in serial.

Multithreading is the ability to send multiple threads out to the scheduler and have it execute them simultaneously. It is an important part of parallel computing. When you create a new thread, that thread will seem to run at the same time as the rest of the code. This can be particularly useful for when you want to run processes that may take a long time, or perhaps even infinite time, side by side, such as important game loops.

spawn(function()
    while true do
        print("Loop a", tick()) --> prints every half second
        wait(0.5)
    end
end)

while true do
    print("Loop b", tick()) --> prints every second
    wait(1)
end

-- notice how although both loops never halt, they run simultaneously thanks to spawn

A task scheduler is essentially a large loop that goes through all of the processes it has to do and executes them. It runs as fast as it possibly can, and in Lua this is a number pretty close to 0.03.

What spawndoes is wait for the current task scheduler update to end. Then, it puts in your request to make a new thread with some code content in it into the task scheduler and will wait until the next task scheduler update. When that update happens, the thread will execute and your code will begin executing. The content of the thread itself is the function you supply to spawn.

spawn(function()
    -- this is the thread that will run simultaneously with the rest of the tasks on the task scheduler
end)

Threads created by spawn are different from coroutine threads. When you create a coroutine, you create a thread but you also get a reference to the thread's associated coroutine that you can manipulate with coroutine functions.

local c = coroutine.create(function()
    -- new thread, coroutine.create should return a reference with type thread
end)
local s = spawn(function()
    -- new thread, spawn should return no reference
end)
print(type(c), type(s)) --> thread nil

spawn does not return such a reference. It's a much more light-weight, RBX.Lua native function construct that simply queues up a new thread to the task scheduler. Once you create it, you cannot get a reference to it and you simply wait until it runs to completion.

Coroutines also run immediately and attempt to create a new thread without waiting for the current task scheduler update to complete. If you are in an environment where small increments of time like 0.03 really matter, you may want to look into coroutines over spawn.

Also note that you cannot directly pass arguments to a thread using spawn. Calling a function within the thread with arguments is a good workaround for this.

local a = 1
local b = 2
spawn(function()
    print(a, b) --> 1, 2
end)
0
How would waiting for the current task scheduler update to end before running affect an actual coding situation? Can you write an example? Perci1 4988 — 9y
0
Say you want to sample the most recent state of an object in parallel. In this scenario, you would want to minimize the amount of time elapsed between your request and the actual sampling. Coroutines would be preferred for accuracy, because a thread is immediately launched rather than waiting for the scheduler to move to the next update. If time doesn't matter, which you use shouldn't matter. Unclear 1776 — 9y
0
"If you are in an environment where small increments of time like 0.03 really matter, you may want to look into coroutines over spawn." As stated in the original response. Unclear 1776 — 9y
0
So each "update" is essentially a line of code being ran? Do delay functions like Wait() affect the task scheduler's update rate? Perci1 4988 — 9y
View all comments (3 more)
0
"A task scheduler is essentially a large loop that goes through all of the processes it has to do and executes them." Each update goes through all processes it has and executes, that's it. "It runs as fast as it possibly can." There is no yielding in the loop, the loop goes as fast as possible and is therefore unaffected by whatever you do. Unclear 1776 — 9y
1
coroutines aren't executed in parallel; they are executed sequentially. I don't think spawn creates true threads, either. "run at the same time" is a really big over simplification. (The rest of this answer is very good) BlueTaslem 18071 — 9y
0
Wait, so if it goes through ALL the processes that would mean spawn() wouldn't run until the script is over. Perci1 4988 — 9y
Ad

Answer this question