Python 如何使用asyncio并行计算?
我有一个代码块,它需要很长时间来执行,并且占用大量CPU。我想运行该块几次,并希望使用我的CPU的全部功率。查看Python 如何使用asyncio并行计算?,python,python-3.x,parallel-processing,python-asyncio,Python,Python 3.x,Parallel Processing,Python Asyncio,我有一个代码块,它需要很长时间来执行,并且占用大量CPU。我想运行该块几次,并希望使用我的CPU的全部功率。查看asyncio我知道它主要用于异步通信,但也是异步任务的通用工具 在下面的示例中,time.sleep(y)是我要运行的代码的占位符。在本例中,每个co例程一个接一个地执行,执行大约需要8秒 import asyncio import logging import time async def _do_compute_intense_stuff(x, y, logger):
asyncio
我知道它主要用于异步通信,但也是异步任务的通用工具
在下面的示例中,time.sleep(y)
是我要运行的代码的占位符。在本例中,每个co例程一个接一个地执行,执行大约需要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)
当我用asyncio.sleep(y)
替换time.sleep(y)
时,它几乎立即返回。使用等待asyncio.sleep(y)
大约需要2秒钟
有没有一种方法可以使用这种方法来并行化我的代码,或者我应该使用
多处理
还是线程化
?我是否需要将time.sleep(y)
放入一个线程中?执行者使用多线程来完成这项任务(或者多线程处理,如果您愿意的话)。Asyncio用于优化经常等待输入、输出操作运行的代码。有时,这可能是写入文件或加载网站
然而,对于cpu密集型操作(不仅仅依赖于等待IO),建议使用类似于线程的东西,而且在我看来,concurrent.futures
提供了一个非常好的包装,它类似于Asyncio的包装
之所以Asyncio.sleep会使代码运行更快,是因为它会启动函数,然后开始检查协程以查看它们是否准备就绪。这不适合CPU密集型操作,因为没有IO可等待
要将以下示例从多处理更改为多线程,只需将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)
这是中提供的示例的简化版本。您不需要使用asyncio。当您遇到等待I/O发生的问题时,Asyncio非常有用。密集的计算不是这样的问题。改用多处理。如果您使用的是一些C扩展支持的库,在执行繁重的计算时会释放GIL,则仅使用线程。Asyncio还需要所有代码配合。每个
wait
都是一个位置,您的任务告诉事件循环,如果其他任务没有等待,它愿意让它们运行time.sleep()
与合作正好相反。它会阻止一切,因此事件循环无法切换任务。asyncio.sleep()
生成一个协同路由。如果你不等待它,它不会做任何事情,所以是的,你会看到一个即时的回报。谢谢@MartijnPieters,它消除了一些困惑!谢谢你。它似乎不知怎么起作用了。这些函数是并行执行的,但不是并行执行的(我猜)。当执行我的函数时,它会占用整个内核20秒。当执行2个函数时,需要1分钟,并且没有一个内核达到100%。有什么想法吗?处理器不会达到100%,因为你在一个单核上。如果您希望满载cpu,请使用多处理。请记住,您可能希望在启动进程之前预处理您的数据,因为当第二个进程运行时,队列之间的通信有时会很棘手。@Benjamin更新了使用多进程的答案。来自Java,线程在每个核心上运行[帮助我理解了Python中进程和线程的区别。但是,我的实际代码不想在进程中运行,因为我使用了无法pickle的类。因为我没有进程间通信,所以我放弃了漂亮的libs,只使用了一个包装器,用Popen
启动脚本并从stdout位于ThreadPoolExecutor
中。由于您的答案解决了所提出的问题,我将接受它。