Synchronous coroutine call

Imagine the following very common situation: you wrote a long and complex function and realized that part of the code should be separated into a separate function for reuse and / or reading. Usually this extra function call does 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 asynchronous call. Extracting it into a separate function now unexpectedly changes the semantics of programs by inserting a new point at which the coroutine is issued, the event loop takes control, and any other coroutine can be scheduled between them.

Example to:

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 previous example, complicated_func not guaranteed to pause between a call to foo() and a call to bar() . After refactoring, this guarantee will be lost.

My question is this: is it possible to call extracted_func() so that it runs immediately, as if its code were inline? Or is there some other way to accomplish such general refactoring tasks without changing the semantics of programs?

+5
source share
1 answer

After refactoring, this guarantee will be lost.

This is actually not the case.

Is it possible to call extract_func () in such a way that it runs immediately, as if its code were inline?

This is already the case.

await some_coroutine() means that some_coroutine is most likely to give you control over the contour of the event, but it won’t do this until it expects the future (for example, some I / O).

Consider the following example:

 import asyncio async def coro(): print(1) await asyncio.sleep(0) print(3) async def main(): loop.call_soon(print, 2) await coro() loop = asyncio.get_event_loop() loop.run_until_complete(main()) 

Notice how 2 is printed between 1 and 3 , as expected.

It also means that you can freeze the event loop by writing this code:

 async def coro(): return async def main(): while True: await coro() 

In this case, the event loop will never be able to run another task.

+7
source

Source: https://habr.com/ru/post/1269436/


All Articles