pythonpython-asyncio

asyncio.run() vs asyncio.get_event_loop().run_until_complete()


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))

Solution

  • 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()