我看过几个关于 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)
上面定义 futures
变量的所有三个变体都获得了相同的结果;我能看到的唯一区别是,对于第三个变体,执行是乱序的(在大多数情况下这无关紧要)。还有其他区别吗?是否存在我不能只使用最简单的变体(协程的简单列表)的情况?
原文由 crusaderky 发布,翻译遵循 CC BY-SA 4.0 许可协议
实际信息:
从 Python 3.7 开始
asyncio.create_task(coro)
为此 添加 了高级函数。您应该使用它而不是其他从 coroutimes 创建任务的方法。但是,如果您需要从任意可等待对象创建任务,则应使用
asyncio.ensure_future(obj)
。旧信息:
ensure_future
对比create_task
ensure_future
是一种从coroutine
创建Task
的方法。它根据参数以不同的方式创建任务(包括使用create_task
用于协程和类似未来的对象)。create_task
是AbstractEventLoop
的抽象方法。不同的事件循环可以以不同的方式实现这个功能。您应该使用
ensure_future
创建任务。只有当您要实现自己的事件循环类型时,您才需要create_task
。更新:
@bj0 指出了 Guido 对这个话题的回答:
然后:
这让我感到惊讶。我使用
ensure_future
的主要动机一直是它是与循环成员create_task
(讨论 包含 一些想法,例如添加asyncio.spawn
asyncio.create_task
)。我还可以指出,在我看来,使用可以处理任何
Awaitable
的通用函数非常方便,而不是仅使用协程。但是,Guido 的回答很明确: “从协程创建任务时,您应该使用适当命名的
loop.create_task()
”协程什么时候应该包装在任务中?
将协程包装在任务中 - 是“在后台”启动此协程的一种方式。这是例子:
输出:
您可以将
asyncio.ensure_future(long_operation())
替换为 ---await long_operation()
以感受差异。