在Python中,是否有一个异步等效于多处理或并发.futures?

在Python中,是否有一个异步等效于多处理或并发.futures?,python,asynchronous,Python,Asynchronous,基本上,我正在寻找一种使用python3协同路由作为后端而不是线程或进程来提供并行映射的东西。我认为在执行高度并行的IO工作时,应该减少开销 当然,类似的东西已经存在,无论是在标准库中还是在一些广泛使用的软件包中?您可以使用(轻量级线程,基本上是协同程序)来实现这一点,或者在它们之上构建更高级别的库: (摘自) 产量: Size of group 3 Hello from Greenlet 31904464 Size of group 3 Hello from Greenlet 31904944

基本上,我正在寻找一种使用python3协同路由作为后端而不是线程或进程来提供并行映射的东西。我认为在执行高度并行的IO工作时,应该减少开销

当然,类似的东西已经存在,无论是在标准库中还是在一些广泛使用的软件包中?

您可以使用(轻量级线程,基本上是协同程序)来实现这一点,或者在它们之上构建更高级别的库:

(摘自)

产量:

Size of group 3
Hello from Greenlet 31904464
Size of group 3
Hello from Greenlet 31904944
Size of group 3
Hello from Greenlet 31905904
Ordered
('task', 0)
('task', 1)
('task', 2)
Unordered
('task', 2)
('task', 1)
('task', 0)
轻量级与适当多核使用的标准约束适用于greenlets与线程。也就是说,它们是并行的,但不一定是并行的

为将来看到这一点的人提供快速编辑,因为Yaroslav在勾勒Python的asyncio和gevent之间的一些差异方面做了大量工作:

为什么gevent使用异步/等待?(这些都是非常主观的,但过去也适用于我)
-不可移植/易于访问(不仅仅是2.X,而是3.5带来了新的关键字)
-async和await有传播和感染代码库的趋势-当其他人为您封装了它时,它在开发和可读性/可维护性方面都非常好
-除此之外,我(个人)觉得gevent的高级界面非常“pythonic”。
-少用绳子吊死自己。在简单的例子中,这两者似乎很相似,但是你越想处理异步调用,你就越有可能搞砸一些基本的东西,并创建竞争条件、锁和意外的行为。无需重新发明绞索。
-Gevent的性能可以通过简单的示例进行扩展,并在许多生产环境中使用和测试。如果您对异步编程了解不多,那么这是一个很好的起点

为什么是asyncio而不是Gevent?
-如果您可以保证Python的一个版本,并且没有访问第三方软件包/pip的权限,那么它将为您提供开箱即用的支持。
-与上面类似,如果您不想被束缚在一个采用Py3k速度较慢的项目中,那么滚动您自己的小工具集是一个不错的选择。

-如果你想对事情进行微调,那就由你来负责

免责声明仅定义协同程序的语法和用法。它们需要一个事件循环来运行,这是最有可能的

异步映射 我不知道基于协程的
map
的任何实现。但是,使用以下方法实现基本的
map
功能是很简单的:

这个实现非常简单。它为
iterable
中的每个项目创建一个协程,将它们连接到单个协程中,并在事件循环上执行已连接的协程

所提供的实施涵盖部分案例。然而,它有一个问题。对于LongIterable,您可能希望限制并行运行的协同程序的数量。我不能提出简单的实现,它既高效又能保持秩序,所以我将把它留给读者作为练习

演出 你声称:

我认为在执行高度并行的IO工作时,应该减少开销

它需要证明,因此这里比较了
多处理
实现、
gevent
实现和我基于协同程序的实现。所有测试都是在Python3.5上执行的

使用
多处理实现

from multiprocessing import Pool
import time


def async_map(f, iterable):
    with Pool(len(iterable)) as p:  # run one process per item to measure overhead only
        return p.map(f, iterable)

def func(val):
    time.sleep(1)
    return val * val
使用
gevent
实现:

import gevent
from gevent.pool import Group


def async_map(f, iterable):
    group = Group()
    return group.map(f, iterable)

def func(val):
    gevent.sleep(1)
    return val * val
使用
异步IO实现

import asyncio


def async_map(f, iterable):
    loop = asyncio.get_event_loop()
    future = asyncio.gather(*(f(param) for param in iterable))
    return loop.run_until_complete(future)

async def func(val):
    await asyncio.sleep(1)
    return val * val
测试程序通常是
timeit

$ python3 -m timeit -s 'from perf.map_mp import async_map, func' -n 1 'async_map(func, list(range(10)))'
结果:

  • 可分为
    10项
    项:

    • 多处理
      -1.05秒
    • gevent
      -1秒
    • asyncio
      -1秒
  • 可包含
    100个
    项目:

    • 多处理
      -1.16秒
    • gevent
      -1.01秒
    • asyncio
      -1.01秒
  • 可容纳
    500项
    项:

    • 多处理
      -2.31秒
    • gevent
      -1.02秒
    • asyncio
      -1.03秒
  • 可容纳
    5000个
    项目:

    • 多处理
      -失败(产生5k进程不是个好主意!)
    • gevent
      -1.12秒
    • asyncio
      -1.22秒
  • 可容纳
    50000个
    项目:

    • gevent
      -2.2秒
    • asyncio
      -3.25秒
  • 结论 当程序主要执行I/O而不是计算时,基于事件循环的并发工作速度更快。请记住,当I/O更少且涉及更多计算时,这种差异会更小

    生成进程所带来的开销比基于事件循环的并发所带来的开销要大得多。这意味着你的假设是正确的

    比较
    asyncio
    gevent
    我们可以说
    asyncio
    的开销要大33-45%。这意味着创建greenlet比创建协同程序更便宜


    最后得出结论:
    gevent
    具有更好的性能,但是
    asyncio
    是标准库的一部分。性能上的差异(绝对数字)不是很显著
    gevent
    是一个相当成熟的库,而
    asyncio
    是一个相对较新的库,但它发展很快。

    谢谢!gevent现在集成在主要python发行版中,这不是有点不推荐吗?或者他们合作得好吗?这并不是不推荐的(据我所知!),但这也不是Guido最喜欢的方式,所以你听到的可能更多的是关于这一点。尽管如此,它还是性能优良、经过良好测试、简单易用,并且支持3.3+和2.7+。对Python 3的支持目前处于测试阶段。因此,我想没有什么可以阻止向concurre添加一个协程执行器
    import asyncio
    
    
    def async_map(f, iterable):
        loop = asyncio.get_event_loop()
        future = asyncio.gather(*(f(param) for param in iterable))
        return loop.run_until_complete(future)
    
    async def func(val):
        await asyncio.sleep(1)
        return val * val
    
    $ python3 -m timeit -s 'from perf.map_mp import async_map, func' -n 1 'async_map(func, list(range(10)))'