Documenting async functions outside of asyncio

Currently, async functions and generators are documented entirely in the context of the asyncio module, with no further explanation of how they work internally, or how they could be used in non-asyncio code. However, digging through the relevant PEPs and Lib/asyncio/tasks.py, I was surprised by how little magic is involved (essentially just a coroutine with a bare yield to suspend the current chain of coroutines).

Would it make sense to add an example of non-asyncio use of async functions to the documentation, or are async functions purposely considered the exclusive domain of asyncio?

An example

Here is a simple example that I used to try and understand how async functions work. I am not proposing to add this to the documentation, as I am sure more instructive examples can be found.

import types
import collections

@types.coroutine
def suspend():
    yield

async def produce(k):
    for i in range(k):
        yield i
        await suspend()

async def consume(n, k):
    async for i in produce(k):
        print(f"coro{n}, consume {i}")
    return n

queue = collections.deque()
queue.append(consume(1, 3))
queue.append(consume(2, 5))
while queue:
    coro = queue.popleft()
    try:
        coro.send(None)
    except StopIteration as exc:
        result = exc.value
        print(f"{result=}")
    else:
        queue.append(coro)
1 Like

I like the idea of having a separate guide for choosing asynchronous programming strategies (async/await keywords etc., asyncio on top of that; but separately, select, threading, multiprocessing…), and tutorials for each; then ideally the documentation for asyncio itself would be freed from actually needing to explain any theory.