Lua Coroutine Async Patterns
An async pattern is a coroutine that yields a request and is later resumed with the answer. The coroutine reads like straight-line code, while the resumer supplies each answer in turn.
A yield asks, a resume answers
The coroutine yields a request string. The resumer prints it, then resumes the coroutine with the answer.
local worker = coroutine.create(function()
local name = coroutine.yield("need:name")
print(name)
end)
local ok, request = coroutine.resume(worker)
print(request)
coroutine.resume(worker, "Ada")Two requests are answered in order
The coroutine yields twice. Each resume supplies the answer to the most recent request.
local worker = coroutine.create(function()
local a = coroutine.yield("need:a")
local b = coroutine.yield("need:b")
print(a + b)
end)
coroutine.resume(worker)
coroutine.resume(worker, 5)
coroutine.resume(worker, 7)A dispatcher loop answers every request
The loop reads each request, looks up its answer in a table, and resumes with it. It stops when the coroutine is dead.
local answers = {["need:x"] = 4, ["need:y"] = 6}
local worker = coroutine.create(function()
local x = coroutine.yield("need:x")
local y = coroutine.yield("need:y")
print(x * y)
end)
local ok, request = coroutine.resume(worker)
while coroutine.status(worker) ~= "dead" do
ok, request = coroutine.resume(worker, answers[request])
endExample
local answers = {["user:7"] = "Mia", ["posts:Mia"] = 3}
local worker = coroutine.create(function()
local name = coroutine.yield("user:7")
local count = coroutine.yield("posts:" .. name)
print(name .. " has " .. count .. " posts")
end)
local ok, request = coroutine.resume(worker)
while coroutine.status(worker) ~= "dead" do
ok, request = coroutine.resume(worker, answers[request])
endKey points
- Request: a value the coroutine yields to ask the resumer for something.
- Answer: the value passed to coroutine.resume, which becomes the result of the yield.
- Await shape: yield a request, then keep using the answer as if the wait never happened.
- Resumer: the code that reads each request, finds the answer, and resumes the coroutine with it.
- Order: requests are answered in the order the coroutine yields them.
In this example, the worker first yields the request user:7 and receives Mia as the answer. It then yields posts:Mia and receives 3. The dispatcher loop answers each request from its table until the coroutine is dead, and the worker prints its final line.
Note
no async library is involved here, only yield and resume.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
A coroutine yields "need:n" and is resumed with 8. What does the yield expression evaluate to inside the coroutine?