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())
wait(0.5)
end
end)
while true do
print("Loop b", tick())
wait(1)
end
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()
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()
end)
local s = spawn(function()
end)
print(type(c), type(s))
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)
end)
7 comments
How would waiting for the current task scheduler update to end before running affect an actual coding situation? Can you write an example?
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.
"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.
So each "update" is essentially a line of code being ran? Do delay functions like Wait() affect the task scheduler's update rate?
"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.
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)
Wait, so if it goes through ALL the processes that would mean spawn() wouldn't run until the script is over.