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.