gpt4 book ai didi

python - asyncio.ensure_future vs. BaseEventLoop.create_task vs. 简单协程?

转载 作者:IT老高 更新时间:2023-10-28 21:32:44 25 4
gpt4 key购买 nike

我已经看过几个关于 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 变量的所有三个变体都达到了相同的结果;我能看到的唯一区别是,使用第三种变体时,执行是无序的(在大多数情况下这无关紧要)。还有其他区别吗?在某些情况下我不能只使用最简单的变体(协程的普通列表)吗?

最佳答案

实际信息:

从 Python 3.7 开始 asyncio.create_task(coro) 高级函数 was added以此目的。

您应该使用它来代替从 coroutimes 创建任务的其他方式。但是,如果您需要从任意等待创建任务,则应使用 asyncio.ensure_future(obj)


旧信息:

ensure_future vs create_task

ensure_future 是一种创建 Task 的方法来自 coroutine .它根据参数以不同的方式创建任务(包括使用 create_task 用于协程和类似 future 的对象)。

create_taskAbstractEventLoop 的抽象方法。不同的事件循环可以不同的方式实现这个功能。

您应该使用 ensure_future 来创建任务。仅当您要实现自己的事件循环类型时才需要 create_task

更新:

@bj0 指向 Guido's answer关于这个话题:

The point of ensure_future() is if you have something that could either be a coroutine or a Future (the latter includes a Task because that's a subclass of Future), and you want to be able to call a method on it that is only defined on Future (probably about the only useful example being cancel()). When it is already a Future (or Task) this does nothing; when it is a coroutine it wraps it in a Task.

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.

及以后:

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-named loop.create_task(). Maybe there should be an alias for that asyncio.create_task()?

这让我很惊讶。我一直使用 ensure_future 的主要动机是与循环的成员 create_task 相比,它是更高级别的函数(讨论 contains 一些想法,例如添加 asyncio.spawnasyncio.create_task)。

我还可以指出,在我看来,使用可以处理任何 Awaitable 而不是只处理协程的通用函数非常方便。

然而,Guido 的回答很明确:“从协程创建任务时,您应该使用适当命名的 loop.create_task()

什么时候应该将协程包装在任务中?

在任务中包装协程 - 是“在后台”启动此协程的一种方式。示例如下:

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

您可以将 asyncio.ensure_future(long_operation()) 替换为 await long_operation() 以感受不同。

关于python - asyncio.ensure_future vs. BaseEventLoop.create_task vs. 简单协程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36342899/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com