Adam Parkin
Adam Parkin

Reputation: 18730

asyncio.create_task vs await

I'm having trouble understanding how the asyncio.create_task() function introduced in Python 3.7 is supposed to work. If I do:

import asyncio

async def helloworld():
    print("Hello world from a coroutine!")
    asyncio.create_task(helloworld())

def main():
    loop = asyncio.get_event_loop()
    loop.run_until_complete(helloworld())

if __name__ == "__main__":
    main()

I get:

Hello world from a coroutine! Hello world from a coroutine!

As output (ie the coroutine is run twice). How is this not infinite recursion though? I'd expect to see what I see when I use the await keyword:

import asyncio


async def helloworld():
    print("Hello world from a coroutine!")
    await helloworld()


def main():
    loop = asyncio.get_event_loop()
    loop.run_until_complete(helloworld())


if __name__ == "__main__":
    main()

With this I get:

Hello world from a coroutine! Hello world from a coroutine! Hello world from a coroutine! ... many more lines... Traceback (most recent call last): File "test3.py", line 53, in <module> main() File "test3.py", line 48, in main loop.run_until_complete(helloworld()) File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/base_events.py", line 568, in run_until_complete return future.result() File "test3.py", line 37, in helloworld await helloworld() File "test3.py", line 37, in helloworld await helloworld() File "test3.py", line 37, in helloworld await helloworld() [Previous line repeated 984 more times] File "test3.py", line 36, in helloworld print("Hello world from a coroutine!") RecursionError: maximum recursion depth exceeded while calling a Python object

How is the create_task only being scheduled once, and what is the use case for when you might use it (since it has to be run within a context where the event loop is already running)?

Upvotes: 24

Views: 11491

Answers (2)

ospider
ospider

Reputation: 10401

You could treat asyncio.create_task as a daemon thread in a multi-threaded world. The loop stops when the "main" coroutine stops. So the other daemon threads just quits anyway.

Upvotes: 9

dirn
dirn

Reputation: 20769

The task isn't scheduled once, but the loop only runs until helloworld is complete. You see the message print twice because the loop lets the next task run. After that, the tasks stop running because the loop isn't running anymore.

If you change

loop.run_until_complete(helloworld())

to

loop.create_task(helloworld())
loop.run_forever()

you'll see Hello world from a coroutine! print out repeatedly.

Upvotes: 13

Related Questions