asyncio: yielding future
Once an asyncio
coroutine wants to stop and communicate with the event loop, it uses await obj
(or yield from obj
before Python 3.6).
An obj
should be another coroutine, asyncio.Future
or any custom Future-like object (any object with the __await__
method defined).
async def coroutine():
await another_coroutine()
async def another_coroutine():
future = asyncio.Future()
await future
loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine())
Once the coroutine awaits another one, the second starts to run instead of the first. If it awaits the third one, the third one runs. It goes on and on until some coroutine awaits a future. The future actually yields the value, so the loop finally gains control.
What value does the future yield? It yields itself. Can you yield a future directly? No, it's an internal detail you shouldn't normally worry about.
class Awaitable:
def __await__(self):
future = asyncio.Future()
yield future
# RuntimeError: yield was used
# instead of yield from in task
async def coroutine():
await Awaitable()
loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine())
Why does this error occur? How does asyncio
know it's you who yield the future, not the future itself
There is a simple protection: the future raises the internal flag before yielding.