tl;dr ensure_future let's us execute a coroutine in the background, without explicitly waiting for it to finish. If we need, we can wait for it later or poll for result. In other words, this is a way of executing code in asyncio without await.
It's an asyncio construct that tracks execution of a coroutine in a concrete event loop. When you call create_task , you submit a coroutine for execution and receive back a handle. You can await this handle when you actually need the result, or you can never await it, if you don't care about the result.
coroutine was also deprecated in python 3.7 and scheduled for removal in python 3.10. It already issues a deprecation warning if used.
async def is a new syntax from Python 3.5. You could use await , async with and async for inside async def s. @coroutine is a functional analogue for async def but it works in Python 3.4+ and utilizes yield from construction instead of await . For practical perspective just never use @coroutine if your Python is 3.5+.
Starting from Python 3.7 asyncio.create_task(coro)
high-level function was added for this purpose.
You should use it instead other ways of creating tasks from coroutimes. However if you need to create task from arbitrary awaitable, you should use asyncio.ensure_future(obj)
.
ensure_future
vs create_task
ensure_future
is a method to create Task
from coroutine
. It creates tasks in different ways based on argument (including using of create_task
for coroutines and future-like objects).
create_task
is an abstract method of AbstractEventLoop
. Different event loops can implement this function different ways.
You should use ensure_future
to create tasks. You'll need create_task
only if you're going to implement your own event loop type.
Upd:
@bj0 pointed at Guido's answer on this topic:
The point of
ensure_future()
is if you have something that could either be a coroutine or aFuture
(the latter includes aTask
because that's a subclass ofFuture
), and you want to be able to call a method on it that is only defined onFuture
(probably about the only useful example beingcancel()
). When it is already aFuture
(orTask
) this does nothing; when it is a coroutine it wraps it in aTask
.If you know that you have a coroutine and you want it to be scheduled, the correct API to use is
create_task()
. The only time when you should be callingensure_future()
is when you are providing an API (like most of asyncio's own APIs) that accepts either a coroutine or aFuture
and you need to do something to it that requires you to have aFuture
.
and later:
In the end I still believe that
ensure_future()
is an appropriately obscure name for a rarely-needed piece of functionality. When creating a task from a coroutine you should use the appropriately-namedloop.create_task()
. Maybe there should be an alias for thatasyncio.create_task()
?
It's surprising to me. My main motivation to use ensure_future
all along was that it's higher-level function comparing to loop's member create_task
(discussion contains some ideas like adding asyncio.spawn
or asyncio.create_task
).
I can also point that in my opinion it's pretty convenient to use universal function that can handle any Awaitable
rather than coroutines only.
However, Guido's answer is clear: "When creating a task from a coroutine you should use the appropriately-named loop.create_task()
"
Wrap coroutine in a Task - is a way to start this coroutine "in background". Here's example:
import asyncio
async def msg(text):
await asyncio.sleep(0.1)
print(text)
async def long_operation():
print('long_operation started')
await asyncio.sleep(3)
print('long_operation finished')
async def main():
await msg('first')
# Now you want to start long_operation, but you don't want to wait it finised:
# long_operation should be started, but second msg should be printed immediately.
# Create task to do so:
task = asyncio.ensure_future(long_operation())
await msg('second')
# Now, when you want, you can await task finised:
await task
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Output:
first
long_operation started
second
long_operation finished
You can replace asyncio.ensure_future(long_operation())
with just await long_operation()
to feel the difference.
create_task()
ensure_future()
create_task
,As you can see the create_task is more specific.
async
function without create_task or ensure_futureSimple invoking async
function returns coroutine
>>> async def doit(i):
... await asyncio.sleep(3)
... return i
>>> doit(4)
<coroutine object doit at 0x7f91e8e80ba0>
And since the gather
under the hood ensures (ensure_future
) that args are futures, explicitly ensure_future
is redundant.
Similar question What's the difference between loop.create_task, asyncio.async/ensure_future and Task?
Note: Only valid for Python 3.7 (for Python 3.5 refer to the earlier answer).
From the official docs:
asyncio.create_task
(added in Python 3.7) is the preferable way for spawning new tasks instead ofensure_future()
.
So now, in Python 3.7 onwards, there are 2 top-level wrapper function (similar but different):
asyncio.create_task
: which simply call event_loop.create_task(coro)
directly. (see source code)ensure_future
which also call event_loop.create_task(coro)
if it is coroutine or else it is simply to ensure the return type to be a asyncio.Future. (see source code). Anyway, Task
is still a Future
due to its class inheritance (ref). Well, utlimately both of these wrapper functions will help you call BaseEventLoop.create_task
. The only difference is ensure_future
accept any awaitable
object and help you convert it into a Future. And also you can provide your own event_loop
parameter in ensure_future
. And depending if you need those capability or not, you can simply choose which wrapper to use.
for your example, all the three types execute asynchronously. the only difference is that, in the third example, you pre-generated all 10 coroutines, and submitted to the loop together. so only the last one gives output randomly.
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