25

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

2 Answers 2

13

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.

Sign up to request clarification or add additional context in comments.

9 Comments

Right, so the 2nd time into helloworld we schedule another run of it, but because of the run_until_complete being done control is returned back to main(). Thanks!
"You see the message print twice because the loop lets the next task run." -- is this by accident (undefined behavior under race condition), or is it the expected behaviour, like: finish all started tasks while silently ignoring new calls to create_task?
Does not explain why the loop only lets the next task run and not any subsequent tasks.
@GamefanA because once the first task registers the second task it's done. At that point, run_until_,complete is satisfied and stops running the loop.
@dirn Here is the scenario in my head. First task is ran, which prints and schedules the second task. If it is as you say and the first task is now done, then the loop should exit immediately and not even attempt the second, even though it is queued up. But that doesn't happen! its as if the first task doesn't terminate at the end, but instead yields and gives the second task a chance to run, which in turn schedules a third, and so on and so on... only explanation i could think of is that the first task yields to the second and the second yields back to the first and the first then terminates.
|
9

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.