Paul Paul - 1 month ago 9
Python Question

pyton 3.5 asyncio how interpreter handles 'suspended' corutines

I'm new to asyncio and trying to understand how it actually works.

Lets say we have two corutines and one of them looks like this:

async def f():
await sleep(10)

Instead of
could be any IO operation, obviously.
If I understand this code right, we starting to execute
and switching context to the some other couroutine (if it exists).

But how does interpreter 'counts' that 10 seconds if this coroutine has been suspended? Or how does interpreter handle some IO response, if it happened when coroutine is suspended?


Internally asyncio.sleep() returns a Future object. The future's value will be set after timeout expiring.

Every coroutine is executed by asyncio.Task. The future is bubbled up to task runner (Task._step() actually). The runner adds a callback to bubbled future for waking up itself when future will be done.

sleep() implementation is trivial:

def sleep(delay, result=None, *, loop=None):
    """Coroutine that completes after a given time (in seconds)."""
    if delay == 0:
        return result

    if loop is None:
        loop = events.get_event_loop()
    future = loop.create_future()
    h = future._loop.call_later(delay,
                                future, result)
        return (yield from future)

Task runner is much more complex beast but it's source code is still readable:

Every blocking IO returns a future too (maybe from very deep internal call). When IO waiting is done the given value (or exception) is assigned to the future, task runner is woken up and suspended coroutine is resumed.