Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 502
Adam Parkin Avatar asked Aug 03 '18 21:08

Adam Parkin


People also ask

What is Asyncio Create_task?

The method create_task takes a coroutine object as a parameter and returns a Task object, which inherits from asyncio. Future . The call creates the task inside the event loop for the current thread, and starts the task executing at the beginning of the coroutine's code-block.

What does await do in Asyncio?

The keyword await passes function control back to the event loop. (It suspends the execution of the surrounding coroutine.) If Python encounters an await f() expression in the scope of g() , this is how await tells the event loop, “Suspend execution of g() until whatever I'm waiting on—the result of f() —is returned.

When should I use async await Python?

They are generally used for cooperative tasks and behave like Python generators. An async function uses the await keyword to denote a coroutine. When using the await keyword, coroutines release the flow of control back to the event loop. To run a coroutine, we need to schedule it on the event loop.


1 Answers

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.

like image 183
dirn Avatar answered Sep 17 '22 12:09

dirn