在Windows上使用Python的multiprocessing
时,将许多参数传递给子进程时,它们必须是“可拾取的”。
import multiprocessing
class Foobar:
def __getstate__(self):
print("I'm being pickled!")
def worker(foobar):
print(foobar)
if __name__ == "__main__":
# Uncomment this on Linux
# multiprocessing.set_start_method("spawn")
foobar = Foobar()
process = multiprocessing.Process(target=worker, args=(foobar, ))
process.start()
process.join()
可剥性
确保代理方法的参数可腌。
[...]
比泡菜/腌制更好的继承
使用 spawn 或 forkserver 启动方法时,
multiprocessing
中的许多类型都必须是可腌制的,以便子进程可以使用它们。但是,通常应该避免使用管道或队列将共享对象发送到其他进程。相反,您应该安排程序,以便需要访问在其他位置创建的共享资源的进程可以从祖先进程继承该程序。[...]
更具可选择性
确保
Process.__init__()
的所有自变量都是可选取的。另外,如果您继承Process
的子类,请确保在调用Process.start
方法时实例是可腌制的。
但是,我注意到“ multiprocessing
泡菜”和标准pickle
模块之间有两个主要区别,我很难理解所有这些。
multiprocessing.Queue()
不可“拾取”,但可传递给子进程import pickle
from multiprocessing import Queue, Process
def worker(queue):
pass
if __name__ == "__main__":
queue = Queue()
# RuntimeError: Queue objects should only be shared between processes through inheritance
pickle.dumps(queue)
# Works fine
process = Process(target=worker, args=(queue, ))
process.start()
process.join()
import pickle
from multiprocessing import Process
def worker(foo):
pass
if __name__ == "__main__":
class Foo:
pass
foo = Foo()
# Works fine
pickle.dumps(foo)
# AttributeError: Can't get attribute 'Foo' on <module '__mp_main__' from 'C:\\Users\\Delgan\\test.py'>
process = Process(target=worker, args=(foo, ))
process.start()
process.join()
如果multiprocessing
在内部未使用pickle
,那么这两种对象序列化方式之间的固有区别是什么?
此外,在多处理上下文中“继承”是什么意思?我应该怎么比泡菜更喜欢?
答案 0 :(得分:1)
将multiprocessing.Queue
传递给子进程时,实际发送的是从pipe
获得的文件描述符(或句柄),该文件描述符必须由父级在创建子级之前创建。来自pickle
的错误是为了防止尝试通过另一个Queue
(或类似渠道)发送Queue
,因为那时使用它为时已晚。 (Unix系统实际上确实支持通过某些类型的套接字发送管道,但是multiprocessing
不使用此类功能。)可以肯定的是,某些multiprocessing
类型可以发送给子进程。否则将是无用的,因此没有提及明显的矛盾。
由于“ spawn”启动方法无法使用已创建的任何Python对象创建新进程,因此必须重新导入主脚本以获得相关的函数/类定义。由于明显的原因,它没有将__name__
设置为原始运行,因此任何依赖于该设置的内容将不可用。 (在这里, un 酸洗失败了,这就是您手动酸洗起作用的原因。)
fork 方法从子对象开始,但其父对象(仅在分叉时)仍然存在;这就是继承的意思。