What does async/await do?
async
and@coroutine
functions returns coroutine/generator, not the returned value
To be technical, types.coroutine
returns a generator-based coroutine which is different than generators and different than coroutines.
await extracts the actual return value of coroutine/generator.
await
, similar to yield from
, suspends the execution of the coroutine until the awaitable it takes completes and returns the result.
async function result (coroutines) is meant to be added to event-loop.
Yes.
await creates "bridge" between event-loop and awaited coroutine (enabling the next point).
await creates a suspension point that indicates to the event loop that some I/O operation will take place thereby allowing it to switch to another task.
@coroutine's yield communicates directly with event-loop. (skipping direct caller which awaits the result)
No, generator-based coroutines use yield from
in a similar fashion to await
, not yield
.
await can be used only inside async functions.
Yes.
yield can be used only inside coroutine.
yield from
can be used inside generator-based coroutines (generators decorated with types.coroutine
) and, since Python 3.6, in async
functions that result in an asynchronous generator.
Demo code:
(illustrates whole control flow between async
and types.coroutine
and event loop)
import typesclass EL: """Fake An event loop.""" def __init__(self, outer_async): self.outer_async = outer_async def loop(self): print(' EL.loop : outer_async.send(None)') send_result = self.outer_async.send(None) # seed outer_async. print(' EL.loop : outer_async.send(None) -> outer_async_send_result = {}'.format(send_result)) do_loop = True loop_counter = 0 while do_loop: print() loop_counter += 1 try: arg = send_result + '-loop(send-{})'.format(loop_counter) print(' EL.loop.while : task.outer_async.send({})'.format(arg)) send_result = self.outer_async.send(arg) # raises StopIteration. print(' EL.loop.while : task.outer_async.send({}) -> send_result = {}'.format(arg, send_result)) except StopIteration as e: print(' EL.loop.while : except StopIteration -> {}'.format(e.value)) do_loop = False return loop_counterasync def outer_async(label): inner_coro_arg = label + '-A1' print(' outer_async({}) : await inner_coro({})'.format(label, inner_coro_arg)) await_result = await inner_coro(inner_coro_arg) print(' outer_async({}) : await inner_coro({}) -> await_result = {}'.format(label, inner_coro_arg, await_result)) inner_coro_arg = label + '-A2' print(' outer_async({}) : await inner_coro({})'.format(label, inner_coro_arg)) await_result = await inner_coro(inner_coro_arg) print(' outer_async({}) : await inner_coro({}) -> await_result = {}'.format(label, inner_coro_arg, await_result)) return 555555@types.coroutinedef inner_coro(inner_coro_label): yld_arg = inner_coro_label + '-C(yield)' print(' inner_coro({}) : yield({})'.format(inner_coro_label, yld_arg)) yield_result = yield yld_arg print(' inner_coro({}) : yield({}) -> yield_result = {}'.format(inner_coro_label, yld_arg, yield_result)) return_value = yield_result + '-C(return)' print(' inner_coro({}) : return -> {}'.format(inner_coro_label, return_value)) return return_valuedef main(): loop = EL(outer_async('$$')) print('main() : loop.loop') loop_outer_async = loop.loop() print('main() : loop.loop -> {}'.format(loop_outer_async))if __name__ == '__main__': main()
Result:
main() : loop.loop EL.loop : outer_async.send(None) outer_async($$) : await inner_coro($$-A1) inner_coro($$-A1) : yield($$-A1-C(yield)) EL.loop : outer_async.send(None) -> outer_async_send_result = $$-A1-C(yield) EL.loop.while : task.outer_async.send($$-A1-C(yield)-loop(send-1)) inner_coro($$-A1) : yield($$-A1-C(yield)) -> yield_result = $$-A1-C(yield)-loop(send-1) inner_coro($$-A1) : return -> $$-A1-C(yield)-loop(send-1)-C(return) outer_async($$) : await inner_coro($$-A1) -> await_result = $$-A1-C(yield)-loop(send-1)-C(return) outer_async($$) : await inner_coro($$-A2) inner_coro($$-A2) : yield($$-A2-C(yield)) EL.loop.while : task.outer_async.send($$-A1-C(yield)-loop(send-1)) -> send_result = $$-A2-C(yield) EL.loop.while : task.outer_async.send($$-A2-C(yield)-loop(send-2)) inner_coro($$-A2) : yield($$-A2-C(yield)) -> yield_result = $$-A2-C(yield)-loop(send-2) inner_coro($$-A2) : return -> $$-A2-C(yield)-loop(send-2)-C(return) outer_async($$) : await inner_coro($$-A2) -> await_result = $$-A2-C(yield)-loop(send-2)-C(return) EL.loop.while : except StopIteration -> 555555main() : loop.loop -> 2