loop.create_task、asyncio.async/ensure_future和Task有什么区别?

37
有些asyncio函数让我有点困惑。我看到有一个BaseEventLoop.create_task(coro)函数调度协程。文档中说create_task是新函数,为了兼容性,我们应该使用asyncio.async(coro)。再次参考文档,我发现它是asyncio.ensure_future(coro)的别名,后者也可以调度协程。

与此同时,我一直在使用Task(coro)来调度协程执行,这个方法也运行良好。那么,所有这些之间有什么区别呢?

2个回答

28

正如您所注意到的那样,它们都是做同样的事情。

asyncio.async必须被替换为asyncio.ensure_future,因为在Python >= 3.5中,async已经成为关键字[1]

create_task 的存在理由[2]

第三方事件循环可以使用它们自己的Task子类来实现互操作性。在这种情况下,结果类型是Task的子类。

这也意味着您不应该直接创建一个Task,因为不同的事件循环可能有不同的创建"Task"的方式。

编辑

另一个重要的区别是,除了接受协程外,ensure_future还接受任何可等待对象;而create_task则仅接受协程。


听起来我最好使用ensure_future。谢谢你澄清了这个问题。 - Elektito
1
除非你正在编写适用于Python < 3.4.4的代码,当然啦 ;) - Jashandeep Sohi
啊,是的。我没有注意到!我实际上正在使用Python < 3.4.4;准确地说是3.4.3。 - Elektito
这很反直觉,因为听起来你说要使用ensure_future而不是create_task,所以我进行了研究。在2016年,Guido表示相反的意见。如果你知道你有一个协程并且想要安排它的执行,你应该直接调用create_task。create_task存在的目的是为了第三方循环可以返回一个子类,所以你不应该直接调用任务构造函数。希望这能为其他asyncio新手澄清事情。 - Domino

1

Future

Future是一个对象,它应该在未来拥有结果。

更正式地说:

Future是一个awaitable对象,表示异步操作的最终结果。

如果一个对象可以在await表达式中使用,则该对象是awaitable

因此,任何Future都可以被await

Task

文档:

Tasks用于同时调度协程。

当将协程包装到像asyncio.create_task()这样的函数中时,协程会自动安排在近期运行。

实际上,Task就是一个Future:

运行Python协程的类似Future的对象。

TaskFuture的子类。

asyncio.TaskFuture继承了除了Future.set_result()Future.set_exception()之外的所有API。

create_task(coro)

文档:

coro协程包装到一个Task中并安排其执行。返回Task对象。

asyncio.ensure_future(obj, ...)

它确保obj是一个Future。如果不是,则从obj创建一个Task。就这样。

一些结论

  • 如果obj已经是一个Futureensure_future将返回相同的obj。在这种情况下,函数的返回值可能是Future而不是Task,因为Task只是Future的子类。
  • 使用ensure_future,你可以这样做:
# will create a Task
task = asyncio.ensure_future(coroutine())
# will ensure that it is a Task
task = asyncio.ensure_future(task)

或者这个:
# will create a Task
task = asyncio.create_task(coroutine())
# will ensure that it is a Task
task = asyncio.ensure_future(task)

因此,您可以在Task上调用ensure_future。但是您不能create_task这样做:

# will create a Task
task = asyncio.create_task(coroutine())
# will raise an exception
task = asyncio.create_task(task)

TypeError: 预期是协程,但得到了Task对象

注意

根据文档:

create_task() 是创建新的 Tasks 的首选方式。

自版本3.10起已弃用:如果obj不是类似于Future的对象,loop未指定且没有运行的事件循环,则会发出弃用警告。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接