python pp_python并行计算(上):concurrent.futures、pp模块

本文深入介绍了Python中用于并行计算的concurrent.futures模块和pp模块。concurrent.futures提供了Executor和Future的概念,支持多进程和多线程,其中ProcessPoolExecutor和ThreadPoolExecutor分别用于进程池和线程池的创建。pp模块则通过修改GIL机制实现并行,允许在子进程中直接输出到主进程标准输出。文章详细讲解了这两个模块的使用方法,包括创建进程池、提交任务、获取结果等关键步骤,为后续的并行编程实践奠定了基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于python相当易学易用,现在python也较多地用于有大量的计算需求的任务。本文介绍几个并行模块,以及实现程序并行的入门技术。本文比较枯燥,主要是为后面上工程实例做铺垫。本期介绍concurrent.futures、pp模块。

concurrent.futures模块

1、基本概念

concurrent.futures模块也是一个即可实现多进程,也可用于多线程的模块。以下只介绍多进程,多线程的接口基本相同。

concurrent.futures模块的接口与multiprocessing差异比较大,要理解如何用它,需要搞清楚executor和future两个概念:executor可以类比为multiprocessing的进程池、threading的线程池,相当于一个多进程或多线程的环境。

future对象可以类比为添加到进程池或线程池的一条条具体任务。

2、创建executor和future

(1)创建进程池Executor

concurrent.futures.ProcessPoolExecutor(max_workers=None) #建立进程池Executor。max_workers表示进程池的进程数量限制,缺省为None,表示与CPU数量相同。

concurrent.futures.ThreadPoolExecutor(max_workers=None) #多讲一个线程池Executor的创建。

(2)创建子进程Future

(a)直接提交单个子进程:

XXX.submit(fn, *args, **kwargs) #向进程池提交一个子进程(future对象),子进程直接开始运行,并返回该future对象。future对象对应函数fn(*args, **kwargs)。XXX为进程池Executor。

(b)map方式(同时提交多个子进程):

XXX.map(fn, *iterables, timeout=None, chunksize=1) #并发map函数,返回迭代器(与map(fn,*iterables)返回相同,只是并发执行)。注意这个并行与mulitprocessing模块中的并行也有差异,这里是同批次的子进程同步执行,直到该批次所有进程结束后,才开始下一批次执行。XXX为进程池Executor。

fn:被调函数,

iterables:个数与被调函数的参数个数相同(每个iterable对应一个参数)。

timeout:最大等待时间。缺省为None,表示无限等待。

chunksize:缺省为1,表示iterables中的元素将一次送出1个到进程池。如大于1,则一次送出chunksieze个元素到进程池。对于非常大的iterables,设置较大的chunksize,将显著加快执行速度(只对ProcessPoolExecutor有用。对ThreadPoolExecutor无用,该值忽略)。

(3)with上下文管理

如果直接使用executor和future,多进程执行完成后,最好手动释放资源:

XXX.shutdown() #所有任务完成后,清理并释放进程池Executor相关的资源。

更好的办法是采用with上下文管理:

with concurrent.futures.ProcessPoolExecutor() as executor:

res = executor.map(...)

pp模块

1、基本概念

pp模块(也即parallel python模块)是用纯Python编写的开源、跨平台、轻巧并行模块。

据了解,pp模块实现并行的方式与multiprocessing等不同,他是通过修改pyhton的GIL机制突破这个限制,而非开启多个解释器(未详细确认)。可能也是因为以上原因,pp模块调用子进程中的print函数可以正常输出到主进程标准输出,不像在multiprocessing、multiprocess、pathos.multiprocessing.ProcessPool、concurrent.futures等模块中还必须通过进程间通信传递给主进程操作。

要建立多进程,首先需通过Server类创建进程服务器(类似于进程池);然后,在这个服务中,创建具体的子进程任务Task。

2、建立多进程Server

pp.Server(ncpus='autodetect', ppservers=(), secret=None, restart=False, proto=2, socket_timeout=3600) #建立多进程服务器。ncpus为子进程数量限制。

ncpus:worker processes的数量。缺省为'autodetect',表示自动检测processors的数量。

ppservers:活动的parallel python execution servers的列表。

secret:用于网络连接的口令(passphrase),如果忽略,将使用默认口令。强烈建议使用自定义的口令。

restart:如为True,表示每项任务完成后,重启worker process。

proto:pickle模块的协议代码。

socket_timeout:秒数,表示远程任务执行的最大时间。如果需要运行时间较长的任务,则增大该值;如果远程ppservers经常掉线,则减小该值。

3、建立子进程任务Task

XXX.submit(func, args=(), depfuncs=(), modules=(), callback=None, callbackargs=(), group='default', globals=None) #向多进程服务器XXX提交任务,返回对应该任务的Task实例。submit方法是非阻塞的。

func: 被并行执行的函数

args: func的参数,以元组的形式传入

depfuncs: 被func调用的函数,以元组的形式传入

modules: 函数执行需要调用的模块,以元组的形式传入

callback:回调函数,其参数为(callbackargs, result),result为任务完成的返回值。

callbackargs:回调函数的额外参数。

group:任务分组,用于wait(group)语句的接口(按group阻塞等待完成)。

globals:包含所有模块、函数、类等的dict,比如globals()。

XXX(raw_result=False) #阻塞,直到获取子进程任务XXX的返回值。XXX为Task实例。

由于XXX()是阻塞的,其如果在向多进程Server添加Task过程中调用,将导致每个子进程任务阻塞,任务变为串行。因此,应在所有子进程任务添加完后,再统一调用XXX()获取子进程返回值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值