基本上,我正在寻找一种使用python3协程而不是线程或进程提供并行映射的东西。我认为执行高度并行的IO工作时应该减少开销。
肯定已经存在类似的东西,无论是在标准库中还是在广泛使用的软件包中?
最佳答案
免责声明 PEP 0492仅定义协程的语法和用法。它们需要运行事件循环,最有可能是 asyncio
's event loop。
异步映射
我不知道基于协程的map
的任何实现。但是,使用 map
实现基本的asyncio.gather()
功能很简单:
def async_map(coroutine_func, iterable):
loop = asyncio.get_event_loop()
future = asyncio.gather(*(coroutine_func(param) for param in iterable))
return loop.run_until_complete(future)
此实现非常简单。它为
iterable
中的每个项目创建一个协程,将它们加入单个协程,并在事件循环上执行已加入的协程。提供的实现方案涵盖部分案例。但是它有一个问题。如果长期迭代,您可能希望限制并行运行的协程数量。我无法提出简单的实现方式,该实现方式高效并且可以同时保留顺序,因此我将其作为练习留给读者。
表现
您声称:
它需要证明,因此这里比较了
multiprocessing
实现,a p的gevent
实现和我基于协程的实现。所有测试均在Python 3.5上执行。使用
multiprocessing
的实现: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
使用
asyncio
的实现: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
项:multiprocessing
-1.05秒gevent
-1秒asyncio
-1秒100
项:multiprocessing
-1.16秒gevent
-1.01秒asyncio
-1.01秒500
项:multiprocessing
-2.31秒gevent
-1.02秒asyncio
-1.03秒5000
项:multiprocessing
-失败(生成5k进程不是一个好主意!)gevent
-1.12秒asyncio
-1.22秒50000
项:gevent
-2.2秒asyncio
-3.25秒结论
当程序主要执行I/O而非计算时,基于事件循环的并发工作速度更快。请记住,当I/O更少且涉及更多计算时,差异将更小。
与基于事件循环的并发引入的开销相比,生成过程引入的开销要大得多。这意味着您的假设是正确的。
比较
asyncio
和gevent
可以说,asyncio
的开销大33-45%。这意味着,创建绿色小子比创建协程便宜。最后的结论是:
gevent
具有更好的性能,但是asyncio
是标准库的一部分。性能差异(绝对数字)不是很明显。 gevent
是相当成熟的库,而asyncio
相对较新,但是发展很快。关于python - 在Python中,是否有一个异步于multiprocessing或current.futures?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32955846/