如何使用asyncio并行计算?

时间:2018-07-10 17:53:18

标签: python python-3.x parallel-processing python-asyncio

我有一段代码需要花费很长时间才能执行,并且占用大量CPU。我想多次运行该块,并希望使用CPU的全部功能。看着asyncio,我了解到它主要用于异步通信,但它还是异步任务的通用工具。

在下面的示例中,time.sleep(y)是我要运行的代码的占位符。在此示例中,每个协同程序都一个接一个地执行,并且执行大约需要8秒钟。

import asyncio
import logging
import time


async def _do_compute_intense_stuff(x, y, logger):
    logger.info('Getting it started...')
    for i in range(x):
        time.sleep(y)
    logger.info('Almost done')
    return x * y

logging.basicConfig(format='[%(name)s, %(levelname)s]: %(message)s', level='INFO')
logger = logging.getLogger(__name__)
loop = asyncio.get_event_loop()
co_routines = [
    asyncio.ensure_future(_do_compute_intense_stuff(2, 1, logger.getChild(str(i)))) for i in range(4)]
logger.info('Made the co-routines')
responses = loop.run_until_complete(asyncio.gather(*co_routines))
logger.info('Loop is done')
print(responses)

当我将time.sleep(y)替换为asyncio.sleep(y)时,它几乎立即返回。使用await asyncio.sleep(y)大约需要2秒钟。

是否可以使用这种方法并行化我的代码,还是应该使用multiprocessingthreading?我需要将time.sleep(y)放入线程吗?

1 个答案:

答案 0 :(得分:2)

执行器使用多线程来完成此任务(或者,如果您愿意,可以执行多处理)。 Asyncio用于优化您经常等待输入,输出操作运行的代码。有时可能是写入文件或加载网站。

但是,对于cpu繁重的操作(不仅仅依赖于等待IO),建议使用类似于线程的内容,我认为concurrent.futures为此提供了一个非常好的包装器,并且它类似于Asyncio的包装器。

Asyncio.sleep使代码运行更快的原因是因为它启动了该函数,然后开始检查协程。这不会模拟CPU繁重的操作。

要将以下示例从多处理更改为多线程,只需将ProcessPoolExecutor更改为ThreadPoolExecutor

这是一个多处理示例:

import concurrent.futures
import time

def a(z):
    time.sleep(1)
    return z*12

if __name__ == '__main__':
    with concurrent.futures.ProcessPoolExecutor(max_workers=5) as executor:
        futures = {executor.submit(a, i) for i in range(5)}
        for future in concurrent.futures.as_completed(futures):
            data = future.result()
            print(data)

这是documentation for executors中提供的示例的简化版本。