我有一段代码需要花费很长时间才能执行,并且占用大量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秒钟。
是否可以使用这种方法并行化我的代码,还是应该使用multiprocessing
或threading
?我需要将time.sleep(y)
放入线程吗?
答案 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中提供的示例的简化版本。