0dminnimda
0dminnimda

Reputation: 1453

Difference between ways to run a function asynchronously

What is the difference between?

asyncio.run(func())

and

loop = asyncio.get_event_loop()
loop.run_until_complete(func())

As far as I understand, the difference is that if I use the first example in a program that already has event_loop, then a conflict will occur.

Upvotes: 5

Views: 2968

Answers (1)

dano
dano

Reputation: 94881

Looking at the source for asyncio.run will give you your answer:

def run(main, *, debug=False):
    """Execute the coroutine and return the result.
    This function runs the passed coroutine, taking care of
    managing the asyncio event loop and finalizing asynchronous
    generators.
    This function cannot be called when another asyncio event loop is
    running in the same thread.
    If debug is True, the event loop will be run in debug mode.
    This function always creates a new event loop and closes it at the end.
    It should be used as a main entry point for asyncio programs, and should
    ideally only be called once.
    Example:
        async def main():
            await asyncio.sleep(1)
            print('hello')
        asyncio.run(main())
    """
    if events._get_running_loop() is not None:
        raise RuntimeError(
            "asyncio.run() cannot be called from a running event loop")

    if not coroutines.iscoroutine(main):
        raise ValueError("a coroutine was expected, got {!r}".format(main))

    loop = events.new_event_loop()
    try:
        events.set_event_loop(loop)
        loop.set_debug(debug)
        return loop.run_until_complete(main)
    finally:
        try:
            _cancel_all_tasks(loop)
            loop.run_until_complete(loop.shutdown_asyncgens())
            loop.run_until_complete(loop.shutdown_default_executor())
        finally:
            events.set_event_loop(None)
            loop.close()

As you can see, it throws an Exception if a loop is already running in the current thread, then creates its own loop and calls run_until_complete on it. The other additional parts compared to your second code snippet is that it validates if the function you passed to it is a coroutine, and that it handles shutting everything down cleanly after the coroutine you passed to it has completed.

As its docstring says, it's intended to be used as a entry point into asyncio applications.

Upvotes: 4

Related Questions