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

Spawn and coroutine?

Asked by
LuaQuest 450 Moderation Voter
8 years ago

So basically, I've just been having a hard time decide what i can prioritize when it comes to making a new thread in my script. I know spawn(f) will run "f" as a function in a new thread, but is it faster (or slower) than using coroutine.resume(coroutine.create(f))? For example:

-- Let's say i made a function for running a function in a new thread

local function thread(f)
    coroutine.resume(coroutine.create(f))
end

Now let's say:

thread(function() print'hello' end)
spawn(function() print'hello again' end)

-- Does this mean i just re-created the "spawn" function, or does it have a different use?

Anyway, just something i would really find helpful if answered. Thank you for your time.

1 answer

Log in to vote
3
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
8 years ago

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.

fibs = coroutine.create(function()
    local a, b = 0, 1
    while true do
        coroutine.yield(a)
        a, b = b, a + b
    end
end)

print( coroutine.resume(fibs) ) -- true, 0
print( coroutine.resume(fibs) ) -- true, 1
print( coroutine.resume(fibs) ) -- true, 1
print( coroutine.resume(fibs) ) -- true, 2
print( coroutine.resume(fibs) ) -- true, 3
print( coroutine.resume(fibs) ) -- true, 5
print( coroutine.resume(fibs) ) -- true, 8

The truemeans the coroutine is still alive (the function hasn't actually returned).

The remaining values are what were yielded.

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:

fibs = coroutine.wrap(function()
    local a, b = 0, 1
    while true do
        coroutine.yield(a)
        a, b = b, a + b
    end
end)

print( fibs() ) -- 0
print( fibs() ) -- 1
print( fibs() ) -- 1
print( fibs() ) -- 2
print( fibs() ) -- 3
print( fibs() ) -- 5
print( fibs() ) -- 8

Wait.. Didn't you say only one coroutine runs at a time?

Yes -- so how does spawning 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 yields. 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 resumes 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 waiting)

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 spawning 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.

0
Amazing explanation. You're explanation actually gave me more questions, then answered them along the way. This was very helpful, thank you. LuaQuest 450 — 8y
Ad

Answer this question