Python多进程共享内存性能低于pickling的原因及耗时检测问题
问题1:共享内存版本性能更差的核心原因
- 额外的数据转换开销未被计入局部计时:你在
main_shared里打印的done计时仅统计了pool.map的执行耗时,但整个函数内将原生Python列表转换为RawArray、最后再将RawArray转回Python列表的操作才是耗时大头,你提供的测试数据里pool.map仅耗时7.8s左右,剩下的30s总耗时全部来自这两次全量数据转换。 - fork启动模式下原生多进程的开销本来更低:你使用的是fork启动方式,全局变量
data会通过写时复制机制共享给子进程,只要子进程不修改原数据,根本不会触发额外的内存拷贝。而RawArray属于ctypes类型,无论读写都要经过Python对象和C类型的转换,访问开销远高于原生Python列表。 - 共享内存版本多了两次全量拷贝:worker进程里你先将
RawArray切片转成Python列表传给do_work,处理完又把结果列表写回RawArray,等于每个数据块多了两次全量拷贝,开销已经远超过常规多进程序列化返回结果的开销。
问题2:统计pickling/unpickling耗时的方法
直接调用pickle模块手动对目标数据做序列化/反序列化,叠加计时逻辑即可,示例代码如下:
import pickle, time data, _ = setup() test_block = data[0] # 统计序列化耗时 start = time.time() serialized = pickle.dumps(test_block) serialize_cost = time.time() - start print(f"单块序列化耗时: {serialize_cost:.4f}s") # 统计反序列化耗时 start = time.time() deserialized = pickle.loads(serialized) deserialize_cost = time.time() - start print(f"单块反序列化耗时: {deserialize_cost:.4f}s")
如果要统计整个程序生命周期内的pickle总开销,可以用cProfile运行脚本,查看pickle.dump/pickle.load相关函数的调用总耗时。
额外优化建议
你当前的场景不需要用共享内存,fork模式下的写时复制已经足够降低数据拷贝开销。如果要进一步提升性能,优先将do_work的纯Python循环改为numpy向量化操作,性能提升会远高于多进程调优的效果。
内容的提问来源于stack exchange,提问作者Bubaya
相关产品推荐
相关产品推荐

