multiprocessing with ugly pickle

本文探讨了Python中的并发编程,包括多进程与多线程的区别、全局解释器锁(GIL)的影响、并行处理中的序列化问题及解决方案。此外,还讨论了如何利用多核优势进行高效编程,并提供了使用Python多进程库进行并行编程的实际案例。

Q

  • Is multiprocessing the ultimate solution for concurrency?
  • What are the patterns of concurrent programs?

GIL issues

On multi-core machines, threads will race each other to get the GIL, which make the performance even worse.

Serialization

communication

Tutorials

Other reference

GIL

### 解决 Python `multiprocessing` 模块中的 `_pickle.PicklingError` 错误 在使用 Python 的 `multiprocessing` 模块时,可能会遇到 `_pickle.PicklingError` 错误。此错误通常发生在尝试通过进程池传递不可序列化的对象或函数时。 #### 原因分析 该错误的根本原因在于 Python 使用 pickle 库来序列化和反序列化工件以便跨不同进程传输数据。然而,并不是所有的 Python 对象都能被成功序列化。例如,在 Windows 上启动新进程的方式不同于 Unix 系统,这可能导致某些情况下出现 PicklingError[^3]。 #### 解决策略 ##### 1. 函数定义位置调整 确保要传递给子进程的目标函数是在顶层模块级别定义的,而不是嵌套在其他函数内部。这是因为只有顶级定义的对象才能被正确地 pickled 和 unpickled。 ```python def worker_function(x): # 正确做法:作为全局函数定义 return x * x ``` 而非: ```python def some_other_func(): def inner_worker(x): # 不推荐的做法:内联函数难以被序列化 return x * x with Pool() as p: result = p.map(inner_worker, range(10)) ``` ##### 2. 避免传递 lambda 表达式或其他匿名函数 Lambda 表达式同样不易于被序列化;因此应该避免将其直接用于多进程中。 ```python with Pool(processes=4) as pool: results = pool.map(lambda x: x ** 2, data_list) # 可能引发 PicklingError ``` 改为显式的命名函数形式: ```python def square_number(n): return n ** 2 with Pool(processes=4) as pool: results = pool.map(square_number, data_list) ``` ##### 3. 处理复杂类型的参数 对于复杂的自定义类实例或者其他可能不支持自动序列化的类型,则需手动提供其序列化逻辑或者寻找替代方案。 如果确实需要共享状态,考虑利用 Manager 类提供的代理对象来进行通信,比如列表、字典等容器结构。 ```python from multiprocessing import Process, Manager def update_dict(d, key, value): d[key] = value if __name__ == '__main__': manager = Manager() shared_dict = manager.dict() processes = [] for i in range(5): p = Process(target=update_dict, args=(shared_dict, f'key_{i}', i*i)) processes.append(p) p.start() for proc in processes: proc.join() print(shared_dict) ``` ##### 4. 修改入口脚本保护机制 (仅限 Windows) 为了防止潜在的问题发生,在 Windows 平台上应当始终将创建并启动新的工作线程/进程的操作放在 `if __name__ == "__main__":` 守护语句之后执行。 ```python import multiprocessing as mp def task(arg): pass if __name__ == '__main__': pool = mp.Pool() try: res = pool.map(task, iterable_args) finally: pool.close() pool.join() ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值