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)?
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With