Coroutines
Prerequisites: Iterators
A coroutine is a function that can pause itself with yield and
later resume where it left off. Only one runs at a time — it's
cooperative multitasking, not parallelism.
local co = coroutine.create(function(a, b)
print("started with", a, b)
local c = coroutine.yield(a + b)
print("resumed with", c)
local d, e = coroutine.yield(c * 2)
print("resumed with", d, e)
return "finished"
end)
print(coroutine.resume(co, 1, 2))
print(coroutine.status(co))
print(coroutine.resume(co, 10))
print(coroutine.resume(co, "x", "y"))
print(coroutine.status(co))
print(coroutine.resume(co))
started with 1 2
true 3
suspended
resumed with 10
true 20
resumed with x y
true finished
dead
false cannot resume dead coroutine
coroutine.resume(co, ...)starts or continues the coroutine. It returnstrueplus the values passed toyield(or returned at the end), orfalseplus an error.- Values passed to
resumebecome the results of theyieldthat paused it. - Status is
suspended,running, ordead.
Generators with coroutine.wrap
local function fibonacci(limit)
return coroutine.wrap(function()
local a, b = 0, 1
while a <= limit do
coroutine.yield(a)
a, b = b, a + b
end
end)
end
for n in fibonacci(100) do io.write(n, " ") end
print()
0 1 1 2 3 5 8 13 21 34 55 89
coroutine.wrap returns a function that resumes the coroutine each time
it's called — a perfect iterator. Writing the loop "naturally" with
yield is often much easier than keeping state in a closure.
Producers and consumers
local function producer()
return coroutine.wrap(function()
for _, line in ipairs({"alpha", "beta", "gamma"}) do
coroutine.yield(line)
end
end)
end
local function filter(source, pred)
return coroutine.wrap(function()
for item in source do
if pred(item) then coroutine.yield(item) end
end
end)
end
for item in filter(producer(), function(s) return s:find("a$") end) do
print(item:upper())
end
ALPHA
BETA
GAMMA
Each stage pulls items one at a time from the previous one — a lazy pipeline.