Lua Coroutines: Threads from Beyond
Coroutines in Lua offer a unique model of concurrency: cooperative multitasking. Unlike OS threads, coroutines yield control voluntarily, eliminating race conditions and the need for locks.
Creating and Resuming
local co = coroutine.create(function(x)
print("First run:", x)
local y = coroutine.yield(x * 2)
print("Resumed with:", y)
return x + y
end)
local ok, result = coroutine.resume(co, 10) -- First run: 10
print(result) -- 20
local ok, result = coroutine.resume(co, 5) -- Resumed with: 5
print(result) -- 15
Coroutine vs OS Threads
- No preemption: A coroutine runs until it explicitly yields. No surprise context switches.
- No locks needed: Since only one coroutine runs at a time, shared state access is naturally serialized.
- Lightweight: Each coroutine costs a few kilobytes. You can run thousands simultaneously.
- Deterministic: The execution order is entirely controlled by the programmer.
Async I/O Patterns
Coroutines shine in I/O-bound applications. Wrap blocking calls in a scheduler that yields on I/O and resumes when data is ready:
function async_read(socket)
while not socket:has_data() do
coroutine.yield() -- Let other coroutines run
end
return socket:read()
end
The Power of Cooperative Concurrency
In a world obsessed with parallelism, coroutines remind us that concurrency and parallelism are different beasts. Sometimes, elegant cooperation beats brute-force threading.
