In python, there are 3 main types awaitable objects: coroutines, Tasks, and Futures.
I can await
a coroutine, and also a tasks
.
Awaiting a coroutine
import asyncio
async def nested():
return 42
async def main():
print(await nested()) # will print "42".
asyncio.run(main())
Awaiting a task
import asyncio
async def nested():
return 42
async def main():
task = asyncio.create_task(nested())
await task
asyncio.run(main())
What is the value of wrapping the coroutine in a task in the first place? It looks like they do the same thing.
When would I need to use a task vs a coroutine?
Coroutine is just a function that runs in the context of current awaitable. It can yield execution to the event loop on behalf of the caller (the one who calls await
). Think of a function that is allowed to pause it's thread. You can call one coroutine from another, but they still share the same thread.
Task, on other hand, immediately posts a separate job to an event loop. The task itself is a handle to that job. You may await
a task, but it can run on itself just fine in "parallel" — in single threaded context this means that task can run while other josb are yielding (e.g. waiting for the I/O). Task may complete even before you call await
.
Example without tasks:
job_1 = sleep(5)
job_2 = sleep(2)
# will sleep for 5 seconds
await job_1
# will sleep for another 2 seconds
await job_2
Example with tasks:
job_1 = sleep(5)
job_2 = asyncio.create_task(sleep(2))
# will sleep for 5 seconds
await job_1
# by this time, job_2 is complete
# because previous job has yielded at some point, allowing other jobs to run
# thus await takes no time
await job_2
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