Skip to main content
 首页 » 编程设计

python之多处理忽略 "__setstate__"

2025年05月04日15JustinYoung

我假设 multiprocessing 包使用 pickle 在进程之间发送东西。但是,pickle 会注意对象的 __getstate__ 和 __setstate__ 方法。多处理似乎忽略了它们。它是否正确?我糊涂了吗?

要复制,安装 docker,然后输入命令行

$ docker run python:3.4 python -c "import pickle 
import multiprocessing 
import os 
 
class Tricky: 
    def __init__(self,x): 
        self.data=x 
 
    def __setstate__(self,d): 
        self.data=10 
 
    def __getstate__(self): 
        return {} 
 
def report(ar,q): 
    print('running report in pid %d, hailing from %d'%(os.getpid(),os.getppid())) 
    q.put(ar.data) 
 
print('module loaded in pid %d, hailing from pid %d'%(os.getpid(),os.getppid())) 
if __name__ == '__main__': 
    print('hello from pid %d'%os.getpid()) 
    ar = Tricky(5) 
    q = multiprocessing.Queue() 
    p = multiprocessing.Process(target=report, args=(ar, q)) 
    p.start() 
    p.join() 
    print(q.get()) 
    print(pickle.loads(pickle.dumps(ar)).data)" 

你应该得到类似的东西

module loaded in pid 1, hailing from pid 0 
hello from pid 1 
running report in pid 5, hailing from 1 
5 
10 

我本以为应该是“10”“10”,但实际上是“5”“10”。这意味着什么?

(注意:根据 user3667217 的建议编辑代码以符合编程指南)

请您参考如下方法:

多处理模块可以通过以下三种方式之一启动:spawn、fork 或 forkserver。默认情况下,在 unix 上,它会 fork 。这意味着在新进程诞生时不需要 pickle 任何已经加载到 ram 中的东西。

如果您需要更直接地控制 fork 的发生方式,您需要将启动设置更改为 spawn。为此,创建一个上下文

ctx=multiprocessing.get_context('spawn') 

并将所有对 multiprocessing.foo() 的调用替换为对 ctx.foo() 的调用。当你这样做时,每个新进程都会作为一个新的 python 实例诞生;发送到其中的所有内容都将通过 pickle 发送,而不是直接 memcopy。