I'm trying to find a solution to call async function in a Synchronous context.
And following is my references:
- Python call callback after async function is done
- When using asyncio, how do you allow all running tasks to finish before shutting down the event loop
- https://docs.python.org/zh-cn/3/library/asyncio-task.html
- RuntimeError: This event loop is already running in python
- call async function in main function
But I find that, asyncio.get_event_loop() fails when following asyncio.run(), here is my code to reproduce this issue:
import asyncio async def asyncfunction(n): print(f'before sleep in asyncfunction({ n })') await asyncio.sleep(1) print(f'after sleep in asyncfunction({ n })') return f'result of asyncfunction({ n })' def callback(r): print(f'inside callback, got: {r}') r0 = asyncio.run(asyncfunction(0)) # cause following asyncio.get_event_loop() fail. callback(r0) print('sync code following asyncio.run(0)') r1 = asyncio.run(asyncfunction(1)) # but following asyncio.run() still works. callback(r1) print('sync code following asyncio.run(1)') async def wrapper(n): r = await asyncfunction(n) callback(r) asyncio.get_event_loop().create_task(wrapper(2)) #fail if there is asyncio.run() before print('sync code following loop.create_task(2)') #RuntimeError: There is no current event loop in thread 'MainThread'. asyncio.get_event_loop().create_task(wrapper(3)) #the second call works if there is no asyncio.run() before print('sync code following loop.create_task(3)') # main _all = asyncio.gather(*asyncio.all_tasks(asyncio.get_event_loop())) asyncio.get_event_loop().run_until_complete(_all) I think it might because that the event loop is "consumed" by something somehow, and asyncio.set_event_loop(asyncio.new_event_loop()) might be a workaround, but I'm not sure whether that is an expected usage for end-user to set event loop mannually. And I'm also wondering why and how everything happens here.
After read some of the source code of asyncio.run. I can know why this happens.
But I'm still wondering what is the expected way to call async function in a Synchronous context ?
It seems that the following code works (set a new event loop after each asyncio.run() call) :
asyncio.run(asyncfunction()) asyncio.set_event_loop(asyncio.new_event_loop()) but that is somehow weird, and doesn't seems to be the expected way.
asyncio.run: “ This function always creates a new event loop and closes it at the end.”