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 | local ready = {} |
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:
- nonblocking sockets;
- a scheduler that waits for readiness, often with
selector an event loop; - 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.