Python asyncio.ensure_future 与 BaseEventLoop.create_task 与简单协程?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36342899/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
asyncio.ensure_future vs. BaseEventLoop.create_task vs. simple coroutine?
提问by crusaderky
I've seen several basic Python 3.5 tutorials on asyncio doing the same operation in various flavours. In this code:
我已经看过几个关于 asyncio 的基本 Python 3.5 教程,以各种方式执行相同的操作。在这段代码中:
import asyncio
async def doit(i):
print("Start %d" % i)
await asyncio.sleep(3)
print("End %d" % i)
return i
if __name__ == '__main__':
loop = asyncio.get_event_loop()
#futures = [asyncio.ensure_future(doit(i), loop=loop) for i in range(10)]
#futures = [loop.create_task(doit(i)) for i in range(10)]
futures = [doit(i) for i in range(10)]
result = loop.run_until_complete(asyncio.gather(*futures))
print(result)
All the three variants above that define the futuresvariable achieve the same result; the only difference I can see is that with the third variant the execution is out of order (which should not matter in most cases). Is there any other difference? Are there cases where I can't just use the simplest variant (plain list of coroutines)?
上面定义futures变量的所有三个变体都实现了相同的结果;我能看到的唯一区别是,对于第三个变体,执行是乱序的(在大多数情况下应该无关紧要)。还有其他区别吗?是否存在我不能只使用最简单的变体(协程的简单列表)的情况?
回答by Mikhail Gerasimov
Actual info:
实际信息:
Starting from Python 3.7 asyncio.create_task(coro)high-level function was addedfor this purpose.
为此,从 Python 3.7 开始添加了asyncio.create_task(coro)高级函数。
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).
您应该使用它来代替从 coroutime 创建任务的其他方式。但是,如果您需要从任意 awaitable 创建任务,则应使用asyncio.ensure_future(obj).
Old info:
旧资料:
ensure_futurevs create_task
ensure_future对比 create_task
ensure_futureis a method to create Taskfrom coroutine. It creates tasks in different ways based on argument (including using of create_taskfor coroutines and future-like objects).
ensure_future是一种Task从coroutine. 它根据参数以不同的方式创建任务(包括使用create_taskfor 协程和类似未来的对象)。
create_taskis an abstract method of AbstractEventLoop. Different event loops can implement this function different ways.
create_task是 的抽象方法AbstractEventLoop。不同的事件循环可以不同的方式实现这个功能。
You should use ensure_futureto create tasks. You'll need create_taskonly if you're going to implement your own event loop type.
您应该使用ensure_future来创建任务。create_task仅当您要实现自己的事件循环类型时才需要。
Upd:
更新:
@bj0 pointed at Guido's answeron this topic:
The point of
ensure_future()is if you have something that could either be a coroutine or aFuture(the latter includes aTaskbecause 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 wrapsit 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 aFutureand you need to do something to it that requires you to have aFuture.
关键
ensure_future()是,如果您有一些东西可以是协程或 aFuture(后者包括 aTask因为它是 的子类Future),并且您希望能够调用仅在其上定义的方法Future(可能关于唯一有用的例子是cancel())。当它已经是 aFuture(orTask) 时,它什么也不做;当它是一个协程时,它会将它包装在一个Task.如果您知道自己有一个协程并且希望对其进行调度,那么正确使用的 API 是
create_task(). 您应该调用的唯一时间ensure_future()是当您提供接受协程或 a 的 API(如大多数 asyncio 自己的 API)Future并且您需要对它做一些需要您拥有Future.
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()?
最后,我仍然认为这
ensure_future()是一个很少需要的功能的适当晦涩的名称。从协程创建任务时,您应该使用适当命名的loop.create_task(). 也许应该有一个别名asyncio.create_task()?
It's surprising to me. My main motivation to use ensure_futureall along was that it's higher-level function comparing to loop's member create_task(discussion containssome ideas like adding asyncio.spawnor asyncio.create_task).
这让我很惊讶。我一直使用的主要动机ensure_future是与循环成员相比,它是更高级别的函数create_task(讨论包含一些想法,如添加asyncio.spawn或asyncio.create_task)。
I can also point that in my opinion it's pretty convenient to use universal function that can handle any Awaitablerather than coroutines only.
我还可以指出,在我看来,使用可以处理 anyAwaitable而不仅仅是协程的通用函数非常方便。
However, Guido's answer is clear: "When creating a task from a coroutine you should use the appropriately-named loop.create_task()"
但是,Guido 的回答很明确:“从协程创建任务时,您应该使用适当命名的loop.create_task()”
When coroutines should be wrapped in tasks?
什么时候应该将协程包装在任务中?
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.
您可以替换asyncio.ensure_future(long_operation())为只是await long_operation()为了感受不同。
回答by kwarunek
create_task()
create_task()
- accepts coroutines,
- returns Task,
- it is invoked in context of the loop.
- 接受协程,
- 返回任务,
- 它在循环的上下文中被调用。
ensure_future()
ensure_future()
- accepts Futures, coroutines, awaitable objects,
- returns Task (or Future if Future passed).
- if the given arg is a coroutine it uses
create_task, - loop object can be passed.
- 接受期货、协程、等待对象、
- 返回 Task (或 Future 如果 Future 通过)。
- 如果给定的 arg 是它使用的协程
create_task, - 可以传递循环对象。
As you can see the create_task is more specific.
如您所见,create_task 更为具体。
asyncfunction without create_task or ensure_future
async没有 create_task 或 ensure_future 的函数
Simple invoking asyncfunction returns coroutine
简单调用async函数返回协程
>>> async def doit(i):
... await asyncio.sleep(3)
... return i
>>> doit(4)
<coroutine object doit at 0x7f91e8e80ba0>
And since the gatherunder the hood ensures (ensure_future) that args are futures, explicitly ensure_futureis redundant.
并且由于gather幕后确保 ( ensure_future) args 是期货,因此明确ensure_future是多余的。
Similar question What's the difference between loop.create_task, asyncio.async/ensure_future and Task?
类似问题loop.create_task, asyncio.async/ensure_future 和 Task 有什么区别?
回答by Yeo
Note: Only valid for Python 3.7(for Python 3.5 refer to the earlier answer).
注意:仅对Python 3.7有效(对于 Python 3.5,请参阅较早的答案)。
From the official docs:
来自官方文档:
asyncio.create_task(added in Python 3.7) is the preferable way for spawning new tasks instead ofensure_future().
asyncio.create_task(在 Python 3.7 中添加)是生成新任务而不是ensure_future().
Detail:
细节:
So now, in Python 3.7 onwards, there are 2 top-level wrapper function (similar but different):
所以现在,在 Python 3.7 以后,有 2 个顶级包装函数(相似但不同):
asyncio.create_task: which simply callevent_loop.create_task(coro)directly. (see source code)ensure_futurewhich also callevent_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,Taskis still aFuturedue to its class inheritance (ref).
asyncio.create_task: 直接调用event_loop.create_task(coro)即可。(见源代码)ensure_futureevent_loop.create_task(coro)如果它是协程,它也会调用,否则它只是为了确保返回类型为asyncio.Future。(见源代码)。无论如何,由于它的类继承(ref)Task仍然是一个。Future
Well, utlimately both of these wrapper functions will help you call BaseEventLoop.create_task. The only difference is ensure_futureaccept any awaitableobject and help you convert it into a Future. And also you can provide your own event_loopparameter in ensure_future. And depending if you need those capability or not, you can simply choose which wrapper to use.
好吧,最终这两个包装函数都将帮助您调用BaseEventLoop.create_task. 唯一的区别是ensure_future接受任何awaitable对象并帮助您将其转换为 Future。您也可以event_loop在ensure_future. 根据您是否需要这些功能,您可以简单地选择要使用的包装器。
回答by ospider
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.
对于您的示例,所有三种类型都是异步执行的。唯一的区别是,在第三个示例中,您预先生成了所有 10 个协程,并一起提交给循环。所以只有最后一个随机给出输出。

