Reputation: 6737
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)
print('something')
Instead of sleep()
could be any IO operation, obviously.
If I understand this code right, we starting to execute sleep(10)
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?
Upvotes: 4
Views: 261
Reputation: 17376
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 the future will be done.
sleep()
implementation is trivial:
@coroutine
def sleep(delay, result=None, *, loop=None):
"""Coroutine that completes after a given time (in seconds)."""
if delay == 0:
yield
return result
if loop is None:
loop = events.get_event_loop()
future = loop.create_future()
h = future._loop.call_later(delay,
futures._set_result_unless_cancelled,
future, result)
try:
return (yield from future)
finally:
h.cancel()
Task runner is much more complex beast but it's source code is still readable: https://github.com/python/asyncio/blob/master/asyncio/tasks.py#L223-L300
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.
Upvotes: 4