asyncio.ensure_future与BaseEventLoop.create_task与简单协程? [英] asyncio.ensure_future vs. BaseEventLoop.create_task vs. simple coroutine?
问题描述
我看过一些关于asyncio的基本Python 3.5教程,以各种方式进行相同的操作。
在此代码中:
I've seen several basic Python 3.5 tutorials on asyncio doing the same operation in various flavours. In this code:
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 futures
variable 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)?
推荐答案
实际信息:
从Python 3.7开始 asyncio.create_task(coro)
高级函数 。
您应该使用它代替其他从库鲁时间创建任务的方式。但是,如果需要从任意等待的对象创建任务,则应使用 asyncio.ensure_future(obj)
。
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
是一种创建 Task
来自 协程
。它根据参数以不同的方式创建任务(包括对协程和类似未来的对象使用 create_task
)。
create_task
是 AbstractEventLoop
的抽象方法。不同的事件循环可以以不同的方式实现此功能。
create_task
is an abstract method of AbstractEventLoop
. Different event loops can implement this function different ways.
您应使用 ensure_future
创建任务。仅在要实现自己的事件循环类型时,才需要 create_task
。
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.
更新:
@ bj0指向 Guido关于该主题的答案:
ensure_future()$ c的意义$ c>是如果您有可能将
(可能唯一有用的
作为协程或Future
(后者包括Task
,因为
是Future
的子类),并且您希望能够调用仅在<上定义的方法
code>未来
示例是cancel()
)。当它已经是未来
(或任务
)时,此
不执行任何操作;当它是一个协程时,它会在任务
中包装。
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
.
如果您知道如果您有一个协程并且希望对其进行调度,则
使用的正确API是 create_task()
。您唯一应该让
调用 ensure_future()
的时间是当您提供一个API(例如大多数asyncio自己的API中的
)接受协程或未来
和
,您需要对它做一些事情,要求您拥有未来
。
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 calling ensure_future()
is when you are providing an API (like most
of asyncio's own APIs) that accepts either a coroutine or a Future
and
you need to do something to it that requires you to have a Future
.
及更高版本:
最后,我仍然相信
ensure_future()
是一个
晦涩难懂的名字,对于很少需要的功能。从协程创建
任务时,应使用适当命名的
loop.create_task()
。也许应该为
asyncio.create_task()
?
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
的主要动机是,与循环成员 create_task
相比,它是更高级别的函数(讨论包含一些想法,例如添加 asyncio.spawn
或 asyncio.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
).
我也可以指出,这样做非常方便使用可以处理任何 Awaitable
而不是仅协程的通用函数。
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.
但是,Guido的答案很明确:从协程创建任务时,应使用适当命名的 loop.create_task()
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())
输出:
first
long_operation started
second
long_operation finished
您可以用 await long_operation()代替
来感受不同。 asyncio.ensure_future(long_operation())
You can replace asyncio.ensure_future(long_operation())
with just await long_operation()
to feel the difference.
这篇关于asyncio.ensure_future与BaseEventLoop.create_task与简单协程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!