I worked a lot with async functions in languages other than Python. It's usually very straight-forward and easy to find any answers in internet. It was a surprise that solving a very simple question regarding async in Python took me a day. How to execute an async coroutine in a classic synchronous function?
Async library author's position and CPython's GIL made execution of async functions synchronously harder than required. Instead of an exact answer dozens of answers on StackOverflow explain why it is not possible or a bad idea (and a handful of not working suggestions). Ok-ok, I just need a solution!
I had to understand how asyncio works to solve this. So, this code allows to synchronously wait for execution completion of async coroutine without a hot spin-lock:
Usage:
Tests:
Explanation:
The idea is to run the async coroutine (or any awaitable) in another thread with its own async loop. It is needed only in case if there is already a running loop in the current thread. Otherwise we could safely(?) execute it in the current thread.
So, first try-except tests exactly this: is there a running loop in the current thread? If get_running_loop() throws it means there is no loop and we are free to create one and execute a function there in a simple manner. Otherwise we spawn a thread with its own loop and execute there. The result (including an exception) is passed from the thread via a mutable container, a dictionary.
Tests include both scenarios: calling from sync function w/o a loop in the thread; and calling from async function with a loop.
Comments