User:NecroBumpist/Tutorials/Coroutines
In this custom tutorial, I will demonstrate how to utilize coroutines, a very interesting aspect of Lua.
Description
Coroutines are very similar to subroutines (also known as functions), because they do exactly the same thing, just in a special manner.
What makes coroutines different is that unlike subroutines, coroutines can be executed partially, stopped, and then resumed from where they were at a different time.
With this, you can share execution time in Lua, just like your computer is doing right now.
Creating a Coroutine
Coroutines are actually 'threads' which encompass a normal Lua subroutine, just like Scripts do!
To create a coroutine, you have to use coroutine.create() like so:
local function subroutine() print("Inside a coroutine!"); end local thread = coroutine.create(subroutine); -- this turns subroutine() into a real coroutine
Starting a coroutine
Once you've created a coroutine, you must use coroutine.resume() to begin execution. You can also pass arguments to the coroutine this way. It should be kept in mind that a function can only be executed completely once. Once a function returns the coroutine cannot be started again. (The solution is to recreate the coroutine)
NOTE: coroutine.resume() is like pcall() in that it returns whether or not the function ran properly.
local function subroutine(val) local num; for i = 1, val do num = math.random(); end return num; end local thread = coroutine.create(subroutine); local Work, SecureNumber = coroutine.resume(thread, 500); print(SecureNumber) --> 0.99261452070681
Stopping coroutines mid-execution
Using a combination of coroutine.yield() and coroutine.resume() you can finally use coroutines in the way they were meant to be used.
Together, you will be able to stop a coroutine at a certain point, go do some other work, and then resume the coroutine.
local function subroutine() for i = 1, 3 do coroutine.yield("This coroutine stopped. `i` = " .. i); -- this is where the coroutine stops, and will resume from end end local thread = coroutine.create(subroutine); for i = 1, 3 do print(coroutine.resume(thread)); end Output: true This coroutine stopped. `i` = 1 true This coroutine stopped. `i` = 2 true This coroutine stopped. `i` = 3
It is possible to pass values between a coroutine and its calling thread via coroutine.resume() and coroutine.yield().
local function subroutine(input) print("Coroutine: `input` = " .. input); local secondInput = coroutine.yield("Coroutine is working!"); print("Coroutine: `secondInput` = " .. secondInput); return "Finished!"; end local thread = coroutine.create(subroutine); local midway = coroutine.resume(thread, "Sorcus is EPIC"); print("Main thread: `midway` = " .. midway); local output = coroutine.resume(thread, "Oysi is EPIC as well"); print("Main thread: `output` = " .. output); Output: Coroutine: `input` = Sorcus is EPIC Main thread: `midway` = Coroutine is working! Coroutine: `secondInput` = Oysi is EPIC as well Main thread: `output` = Finished!
Various other functionality
Now you know the basics of how to use coroutines, so practicing with them a little is advised, but there is still more to learn. There are several other secondary coroutine functions which can be quite useful. I will describe these briefly here, follow the links to learn more.
coroutine.running()
coroutine.running() returns the thread for the currently executing coroutine, or nil if called from the main thread.
coroutine.status(co)
coroutine.status() returns a string describing the state of the current thread, whether it is capable of being ran, paused, or dead.
coroutine.wrap(f)
coroutine.wrap() combines the abilites of coroutine.resume() and coroutine.create(), in that it returns a function that will resume the function it is provided.