Imagine the following very common situation: you have written a long and complicated function and realize that some of the code should be extracted into a seperate function for reuse and/or readability. Usually, this extra function call will not change the semantics of your program.
However, now imagine that your function is a coroutine and the code you want to extract contains at least one asyncronous call. Extracting it into a separate function now suddenly changes your programs semantics by inserting a new point on which the coroutine yields, the event loop takes control and any other coroutine could be scheduled in between.
Example before:
async def complicated_func():
foo()
bar()
await baz()
Example after:
async def complicated_func():
foo()
await extracted_func()
async def extracted_func():
bar()
await baz()
In the example before, the complicated_func
is guaranteed not to be suspended between calling foo()
and calling bar()
. After refactoring, this guarantee is lost.
My question is this: is it possible to call extracted_func()
such that it is executed immediately as if its code would be inline? Or is there some other way to perform such common refactoring tasks without changing the programs semantics?
It's actually not.
That's already the case.
await some_coroutine()
means thatsome_coroutine
is likely to give to control back to the event loop, but it's not going to do so until it actually awaits a future (e.g some I/O operation).Consider this example:
Notice how
2
gets printed between1
and3
as expected.That also means it's possible to freeze the event loop by writing such code:
In this case, the event loop never gets a chance to run another task.