asyncio.ensure_future与BaseEventLoop.create_task与简单协程? [英] asyncio.ensure_future vs. BaseEventLoop.create_task vs. simple coroutine?

查看:148
本文介绍了asyncio.ensure_future与BaseEventLoop.create_task与简单协程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看过一些关于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()是如果您有可能将
作为协程或 Future (后者包括 Task ,因为
Future 的子类),并且您希望能够调用仅在<上定义的方法
code>未来
(可能唯一有用的
示例是 cancel())。当它已经是未来(或任务)时,此
不执行任何操作;当它是一个协程时,它会在任务包装

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.

如果您知道如果您有一个协程并且希望对其进行调度,则
使用的正确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-named loop.create_task(). Maybe there should be an alias for that asyncio.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆