First, a digression:
- Lua does not have threads -- only one coroutine runs at a time
- Coroutines are way more powerful than running two pieces of code "at the same time"
Coroutines work by adding a "pause & play" mechanic to functions. It let's one function "return" many times. coroutine.resume
is analogous to calling the function and coroutine.yield
is analogous to returning a value.
01 | fibs = coroutine.create( function () |
09 | print ( coroutine.resume(fibs) ) |
10 | print ( coroutine.resume(fibs) ) |
11 | print ( coroutine.resume(fibs) ) |
12 | print ( coroutine.resume(fibs) ) |
13 | print ( coroutine.resume(fibs) ) |
14 | print ( coroutine.resume(fibs) ) |
15 | print ( coroutine.resume(fibs) ) |
The true
means the coroutine is still alive (the function hasn't actually returned).
The remaining values are what were yield
ed.
Notice that this seems very much like a function call!
In fact, you want that so often Lua provides coroutine.wrap
which would make the above look like the following:
01 | fibs = coroutine.wrap( function () |
Wait.. Didn't you say only one coroutine runs at a time?
Yes -- so how does spawn
ing a new coroutine let you do two things at once?
The key is how wait
works.
What actually happens when you wait
is that the current coroutine yield
s. Since no thread is running at that point, ROBLOX decides which thread is supposed to work next (based on which has been waiting long enough, etc), and resume
s that one.
Why does all this matter
As I said, coroutine.resume
is like a function call. spawn
is a little different. While ultimately coroutine.resume(coroutine.create(f))
and spawn(f)
act very similarly, there's an important difference.
coroutine.resume
will immediately invoke the function (because it needs to -- because it's supposed to be able to get a result out, it has to). spawn
just records a new "thread" that ROBLOX will watch, and resume when it next gets a chance (when this thread yields, e.g., by wait
ing)
This means that spawn
can have some amount of latency on its function beginning, but coroutine.resume
won't.
However, this shouldn't be a problem. Again, since only one coroutine runs at a time, it shouldn't really make a difference which one you use. If you need to make something happen immediately, just do that before spawn
ing the thread.
Once the coroutines are running, they're completely equal. Neither will do better than the other.
Microoptimization
"Premature optimization is the root of all evil" - Donal Knuth
If you were working with numbers and you were wondering,
Which is faster, x ^ 0.5
or math.sqrt(x)
?
Don't.
Applying all of those optimizations makes your code much harder to deal with -- for people trying to help you and yourself.
If you are just making a new 'thread', it's probably wise to use spawn
-- it shows precisely that you're creating a new thread and not using the power of coroutines.
Also see
delay
is similar to spawn
, but let's you say how far in the future you want the function to happen. delay(t, f)
is like tacking a wait(t)
to the beginning of f
.