I need to call an async function from within a synchronous function.
Can someone educate me on the following: What are the salient differences between sync_fn_a
and sync_fn_b
, and when would I choose one over the other?
async def my_async_fn(arg1):
# internals are not important
def sync_fn_a(arg):
asyncio.run(my_async_fn(arg))
def sync_fun_b(arg):
asyncio.get_event_loop().run_until_complete(my_async_fn(arg))
The first thing I should mention is that asyncio.get_event_loop has been deprecated as of version Python 3.12. You should use instead asyncio.new_event_loop as follows:
def sync_fun_b(arg):
loop = asyncio.new_event_loop() # Create a new event_loop
# Set it as the current event loop so that it will be returned
# when asyncio.get_running_loop is called:
asyncio.set_event_loop(loop)
loop.run_until_complete(my_async_fn(arg)) # Add missing )
asynio.run
will essentially execute the sequence of operations as shown in sync_fun_b
above, i.e. create a new event loop, set the current event loop and run until complete a coroutine. But in addition, after run_until_complete
returns, asyncio.run
will issue a close
method call on the event loop. Consequently every time you call asyncio.run
a new event loop has to be created. If you will be calling multiple async coroutines in succession from a "regular" non-async function, then the following would be more efficient than calling asynci.run
twice because an event loop is created only once and reused:
import asyncio
async def coro1():
...
async def coro2():
...
def main():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
loop.run_until_complete(coro1())
loop.run_until_complete(coro2())
finally:
loop.close()
if __name__ == '__main__':
main()