How does a loop await a sequence of values that arrive over time?¶
Level: 201 · anyone who wants for over a channel in async code
Stub — a question and its expected answers, not yet a lesson. No program behind this page has been written or run, so nothing on it has been through the check that backs every finished page. The table is what the finished lesson is expected to find, and every cell is unverified until a program prints it. (Not machine-checked here.)
One line: An async stream is an iterator whose next is awaited — the values arrive over time and the loop yields between them — and it is where the languages' async designs are furthest apart: Python has async for, Rust has a Stream trait outside the standard library, Go has a channel and needs nothing else, and Java has Flow.Publisher with request-N backpressure.
The question¶
A source produces a value every 100 ms, ten times. A consumer loops over them, awaiting each. The page writes the source and the loop in each language and confirms the ten values arrived in order, then asks the stream's two hard questions: what happens when the consumer is slower than the source, and how the loop ends.
What each language is expected to say¶
| Expected answer, to be verified by the program | |
|---|---|
| Rust | no Stream in std; futures::Stream and while let Some(x) = s.next().await (link, not run); the std column uses a channel on a thread |
| Go | for x := range ch over a channel fed by a goroutine |
| C | a read loop on a pipe |
| C++ | a C++20 generator-style coroutine, hand-rolled promise type; std::generator is C++23 |
| Java | Flow.Publisher and a Subscriber calling request(1) |
| Python | async for x in agen() over an async def with yield |
What the programs have to show¶
- ten values at 100 ms intervals, received in order
- the slow consumer: the source waits (backpressure) or runs ahead, per design
- the end: the generator returning, the channel closing,
onComplete
See also¶
- Before this: What happens to a task that is started and never awaited?
- After this: Who runs an async task, and on how many threads?
- How does a receiver learn that no more values will come?
- How does one event reach every subscriber?
- The Rust library's Streams, sinks, and pipelining ↗
- The Go library's Closing a channel ends a range ↗
- Concepts: Async stream · Backpressure · Channel · Reactive programming · Coroutine