Multiprocessing:多参数函数使用process_map的传参方案疑问
解答
你当前通过元组打包多参数、在目标函数内解包的写法完全正确,是适配process_map传参逻辑的常规实现,不存在正确性问题,可以稳定使用。
process_map的传参逻辑和Python标准库的map、ProcessPoolExecutor.map保持一致:每次只会从传入的可迭代对象里取出单个元素传给目标函数。因此把多个参数打包成单个元组传入、函数内部拆包使用,是完全符合接口设计的标准用法,不属于取巧的hack写法。
如果觉得这种写法需要修改业务函数的原生签名、影响可读性,可以参考两种更友好的替代实现:
- 抽离通用解包包装器,保留业务函数原有签名
不需要在每个业务函数里重复写解包逻辑,单独实现一个通用的参数展开包装函数即可,示例代码如下:
注意:多进程场景下不要用lambda表达式做包装,lambda无法被多进程模块正常序列化,会直接抛出运行错误。from tqdm.contrib.concurrent import process_map import multiprocessing as mp import time # 业务函数保持原生多参数写法,不需要为适配进程池做修改 def _foo(my_number1, my_number2): square = my_number1 * my_number2 time.sleep(1) return square # 单任务专用包装写法 def _foo_pack(args): return _foo(*args) if __name__ == "__main__": r = process_map( _foo_pack, [(i,j) for i,j in zip(range(0,30),range(100,130))], max_workers=mp.cpu_count() ) - 固定参数场景使用
functools.partial
如果传入的参数里有一部分是全局固定值、不需要随任务动态变化,可以直接用functools.partial把固定参数绑定到目标函数上,完全不需要打包元组,示例:from functools import partial from tqdm.contrib.concurrent import process_map import multiprocessing as mp import time def _foo(my_number1, my_number2): square = my_number1 * my_number2 time.sleep(1) return square if __name__ == "__main__": # 绑定固定参数my_number2=100,此时函数仅需传入单个可变参数 _foo_fixed = partial(_foo, my_number2=100) r = process_map( _foo_fixed, range(0,30), max_workers=mp.cpu_count() )
另外你给出的示例代码有两个容易踩的小问题:一是使用了mp.cpu_count()但没有提前导入multiprocessing as mp,直接运行会触发名称错误;二是Windows系统下多进程代码必须放在if __name__ == "__main__":作用域内,否则会出现递归启动进程的异常。
内容的提问来源于stack exchange,提问作者Stef1611
相关产品推荐
相关产品推荐

