Nanfeng

Notes on software development, code, and curious ideas

Cooperative Multitasking with Lua Coroutines

Lua coroutines provide cooperative multitasking. coroutine.yield hands control back to a scheduler, and coroutine.resume continues the suspended function. They are lightweight and make synchronization explicit, but they do not run Lua code in parallel by themselves.

A minimal scheduler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
local ready = {}

local function spawn(fn)
ready[#ready + 1] = coroutine.create(fn)
end

local function run()
while #ready > 0 do
local co = table.remove(ready, 1)
local ok, err = coroutine.resume(co)
if not ok then error(err) end
if coroutine.status(co) ~= "dead" then
ready[#ready + 1] = co
end
end
end

spawn(function()
for i = 1, 3 do
print("A", i)
coroutine.yield()
end
end)

spawn(function()
for i = 1, 3 do
print("B", i)
coroutine.yield()
end
end)

run()

The output interleaves because each task voluntarily yields. A CPU-heavy loop that never yields still blocks every other coroutine.

Asynchronous I/O

Coroutines become especially useful when an event loop or a nonblocking I/O library resumes them after a socket, timer, or file operation is ready. Merely wrapping a blocking HTTP request in a coroutine does not make it nonblocking: the entire Lua state remains blocked until that request returns.

A real downloader therefore needs three pieces:

  1. nonblocking sockets;
  2. a scheduler that waits for readiness, often with select or an event loop;
  3. coroutine wrappers that yield while an operation would block and resume when it can continue.

Always inspect the boolean result from coroutine.resume; uncaught errors are returned to the resumer rather than automatically raised there. Also ensure yields happen outside sections that must remain logically atomic.

Use operating-system threads or multiple processes when true CPU parallelism is required. Use coroutines when the main challenge is expressing many waiting operations as readable sequential code.

+