Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

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

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

✓ Accepted answer

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 spawn does 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)

7 comments

0

How would waiting for the current task scheduler update to end before running affect an actual coding situation? Can you write an example?

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.

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.

0

So each "update" is essentially a line of code being ran? Do delay functions like Wait() affect the task scheduler's update rate?

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.

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)

0

Wait, so if it goes through ALL the processes that would mean spawn() wouldn't run until the script is over.

This discussion is preserved as it was. New answers, comments, and votes are closed.