Python多进程改造后速度未提升,如何优化全局字典写入?
问题分析与优化方案
嘿,我来帮你捋捋这个问题~ 你用多进程重构后速度没提升,大概率不是写入全局字典的锅(毕竟父进程里的字典写入是O(1)操作,开销极低),咱们一步步拆解可能的原因和优化方案:
先搞清楚为什么多进程没提速?
首先排除几个常见坑:
- 进程池没充分利用CPU核心:Python的
multiprocessing.Pool默认进程数是CPU核心数,但如果你没显式设置,或者你的alist里任务数量太少,可能没跑满并行度。 imap的顺序等待特性:imap会严格按照输入列表的顺序返回结果——如果某个子进程处理任务慢,后面的结果哪怕已经处理完,也要等前面的结果返回后才会输出,看起来就像串行一样。- 进程间通信(IPC)开销过大:如果
process2返回的output数据量很大,子进程和父进程之间传递数据需要序列化(Python2.7用cPickle),这个开销会吃掉并行带来的收益。 - 全局变量的拷贝开销:虽然
process只读全局变量,但Mac上Python2.7用fork创建子进程时,会拷贝父进程的全部内存空间——如果你的全局变量很大,每个子进程启动时的拷贝开销会非常高。
针对性优化方案
1. 显式设置进程池大小
先把进程池拉满到CPU核心数,确保用到全部硬件资源:
import multiprocessing if __name__ == '__main__': # 获取CPU核心数 pool_size = multiprocessing.cpu_count() with multiprocessing.Pool(pool_size) as pool: # 后续逻辑...
2. 改用imap_unordered代替imap
如果结果的顺序对你不重要,用imap_unordered可以跳过顺序等待,只要子进程处理完就返回结果,能显著提升整体速度:
for a, output in pool.imap_unordered(process2, alist): main_dict[a] = output
3. 优化进程间通信与字典写入
如果output数据量大,或者你觉得循环写入字典有开销,可以先把所有结果收集到列表,再一次性转成字典——这样比循环写入更高效:
# 先收集所有结果 results = list(pool.imap_unordered(process2, alist)) # 一次性转字典 main_dict = dict(results)
4. 减少全局变量的拷贝开销
如果你的全局变量很大,别让子进程拷贝整个内存空间,改成把全局变量作为参数传递给process2(如果能拆分的话),或者用共享内存存储只读数据:
import itertools # 把全局变量作为参数传入 def process2(a, global_data): output = process(a, global_data) return (a, output) # 启动进程池时传递全局数据 for a, output in pool.imap_unordered(process2, alist, itertools.repeat(global_data)): main_dict[a] = output
5. 排查process函数本身的瓶颈
最后确认下:process函数是不是CPU密集型?如果它本身是IO密集型(比如读写文件、网络请求),那多线程反而可能更适合(Python2.7里用threading.Thread或者multiprocessing.dummy.Pool——这是基于线程的池)。
额外注意事项
Python2.7的多进程在Mac上用fork模式,记得把主逻辑放在if __name__ == '__main__':块里,避免子进程重复执行初始化代码导致奇怪的问题。
内容的提问来源于stack exchange,提问作者TheRajVJain
相关产品推荐
相关产品推荐

