在Python中,是否有一个异步等效于多处理或并发.futures?
基本上,我正在寻找一种使用python3协同路由作为后端而不是线程或进程来提供并行映射的东西。我认为在执行高度并行的IO工作时,应该减少开销 当然,类似的东西已经存在,无论是在标准库中还是在一些广泛使用的软件包中?您可以使用(轻量级线程,基本上是协同程序)来实现这一点,或者在它们之上构建更高级别的库: (摘自) 产量:在Python中,是否有一个异步等效于多处理或并发.futures?,python,asynchronous,Python,Asynchronous,基本上,我正在寻找一种使用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 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秒多处理
-1秒gevent
-1秒asyncio
100个项目:
多处理
-1.16秒
gevent
-1.01秒
asyncio
-1.01秒
500项
项:
-2.31秒多处理
-1.02秒gevent
-1.03秒asyncio
5000个项目:
多处理
-失败(产生5k进程不是个好主意!)
gevent
-1.12秒
asyncio
-1.22秒
50000个项目:
gevent
-2.2秒
asyncio
-3.25秒
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)))'