Coroutine
- Pronunciation
- KOH-roo-teen
In short
A coroutine is a function that can pause partway, hand control back, and later resume where it stopped, so many tasks can take turns on just a few threads.
What is a coroutine?
A normal function runs from start to finish once it is called. A coroutine can suspend itself partway, at points it marks explicitly, and be resumed later with all its local variables intact. Melvin Conway coined the term in 1958, and the idea now sits underneath generators, async/await and Kotlin's coroutines.
Coroutines use cooperative multitasking: each one runs until it chooses to pause, typically while it waits for a network response or a timer, and a scheduler, often an event loop, then runs another coroutine that is ready. Switching only saves a little state, with no operating system involved, so a program can run thousands or even millions of coroutines on a handful of threads. In Python, async def defines a coroutine and each await is a point where it may pause; Kotlin marks pausable functions with suspend, C++20 added co_await and co_yield, and Lua has coroutine.yield.
Picture a chess master playing many boards at once: she makes a move, walks to the next board while that opponent thinks, and later returns to find each game exactly as she left it. Coroutines power servers that juggle many network connections, generators that produce values one at a time, game scripts that wait a few frames, and interfaces that must keep responding while data loads.
Coroutines are often confused with threads. The operating system schedules threads preemptively, meaning it can interrupt them at any instruction, and threads can run in parallel on several cores; coroutines switch only where they choose to, so the code between two pauses never interleaves with other coroutines on the same thread. The flip side is that a coroutine doing long CPU work without pausing blocks everything else on its thread. Async/await is the syntax many languages use for coroutines, while Go's goroutines, despite the name, behave more like lightweight threads.
Key takeaways
- A coroutine can pause partway and later resume with its local state intact.
- Coroutines give up control voluntarily, which is called cooperative multitasking.
- They are far cheaper than threads, so a program can run thousands of them.
- Python's async functions and generators and Kotlin's suspend functions are all forms of coroutines.
- A coroutine that never pauses blocks every other coroutine on its thread.
Example
import asyncio
async def download(name, seconds):
print(f"{name}: started")
await asyncio.sleep(seconds) # pause here; the event loop runs the other one
print(f"{name}: finished") # resume later with every local variable intact
return name
async def main():
# Both coroutines run on a single thread, taking turns
results = await asyncio.gather(download("a", 2), download("b", 1))
print(results) # ['a', 'b'] after about 2 seconds, not 3
asyncio.run(main())Readers ask
What is the difference between a coroutine and a thread?
The operating system schedules threads, can interrupt them at any moment and can run them in parallel. Coroutines are scheduled by the program, switch only at the points they choose and use far less memory, so you can run many more of them. Many runtimes run coroutines on top of a small pool of threads.
Are goroutines coroutines?
Not quite. Goroutines are lightweight threads managed by the Go runtime: since Go 1.14 the runtime can interrupt them, and they run in parallel across CPU cores. The name is a play on the word coroutine.
Is async/await the same as coroutines?
Async/await is syntax for writing coroutines. In Python, calling an async def function returns a coroutine object, and each await is a point where it can pause; C#, JavaScript and Rust turn async functions into similar pausable state machines.
See also
- ThreadOperating Systems, p. 33A thread is the smallest unit of execution an operating system can schedule, running inside a process and sharing that process's memory with other threads.
- Async/AwaitProgramming Fundamentals, p. 5Async/await is a syntax for writing asynchronous code that reads like ordinary step-by-step code, pausing at each await until a promise or task finishes.
- ConcurrencyProgramming Fundamentals, p. 15Concurrency is a program's ability to make progress on several tasks in overlapping time periods, such as serving many users at once rather than one at a time.
- Event LoopBackend & APIs, p. 16The event loop is a mechanism that lets a single thread handle many tasks by running callbacks one at a time as events and I/O results become ready.
- PromiseProgramming Fundamentals, p. 52A promise is an object that represents the eventual result of an asynchronous operation, letting code react to success or failure once the work completes.
- IteratorProgramming Fundamentals, p. 36An iterator is an object that lets code step through the items of a collection one at a time, remembering its position, without exposing how the data is stored.
Sources
Spotted a mistake or something missing on this page?Suggest an edit