在类实例中通过 self 传递参数,同时在 Python 中进行多处理



它似乎有效,但是在分叉后使用self安全吗?还是我应该始终通过args将参数作为函数参数传递给子进程?

import multiprocessing as mp
class C():
def __init__(self):
self.v = 'bla'
p = mp.Process(target=self.worker, args=[])
#p = mp.Process(target=self.worker, args=(self.v,))
p.start()
p.join()
def worker(self):
print(self.v)
#def worker(self, v):
#print(v)
c = C()
# prints 'bla'

更具体地说,我想通过经理。队列(( 对象,不确定,它是否有区别。

如果这是一个简单的C fork((,因为整个过程的复制方式相同 - 除了pid -self将是相同的。但是 Python 多处理可能正在做一些我不知道的事情,或者可能会在某个地方发出警告,例如"不要这样使用它,将来可能会改变"。我没有找到任何专门解决这个问题的东西。

我真正担心的是args传递的参数,特别是如果它们与多处理模块相关联,可能会围绕fork((进行转换以避免任何问题。

蟒蛇 3.6.5

对于forkstart 方法以外的任何方法,当调用Process.start()时,目标和参数都会使用 picking 发送到工作进程。对于fork方法,子进程在同一点分叉,因此在调用Process.start()时。

因此,当您不使用分叉启动方法时,您需要担心的是您的数据是否可以被腌制。在这种情况下,没有理由避免使用类实例和self;整个实例被腌制,因为self.target是一个包含对实例的引用的方法:

>>> class C:
...     def __init__(self):
...         self.v = 'bla'
...     def worker(self):
...         print(self.v)
...
>>> c = C()
>>> data = pickle.dumps(c.worker)
>>> pickletools.dis(data)
0: x80 PROTO      4
2: x95 FRAME      71
11: x8c SHORT_BINUNICODE 'builtins'
21: x94 MEMOIZE    (as 0)
22: x8c SHORT_BINUNICODE 'getattr'
31: x94 MEMOIZE    (as 1)
32: x93 STACK_GLOBAL
33: x94 MEMOIZE    (as 2)
34: x8c SHORT_BINUNICODE '__main__'
44: x94 MEMOIZE    (as 3)
45: x8c SHORT_BINUNICODE 'C'
48: x94 MEMOIZE    (as 4)
49: x93 STACK_GLOBAL
50: x94 MEMOIZE    (as 5)
51: )    EMPTY_TUPLE
52: x81 NEWOBJ
53: x94 MEMOIZE    (as 6)
54: }    EMPTY_DICT
55: x94 MEMOIZE    (as 7)
56: x8c SHORT_BINUNICODE 'v'
59: x94 MEMOIZE    (as 8)
60: x8c SHORT_BINUNICODE 'bla'
65: x94 MEMOIZE    (as 9)
66: s    SETITEM
67: b    BUILD
68: x8c SHORT_BINUNICODE 'worker'
76: x94 MEMOIZE    (as 10)
77: x86 TUPLE2
78: x94 MEMOIZE    (as 11)
79: R    REDUCE
80: x94 MEMOIZE    (as 12)
81: .    STOP
highest protocol among opcodes = 4

在上面的流中,您可以清楚地看到v'blah'worker命名。

如果您确实使用forkstart 方法,则子进程仅具有对父进程中内存中所有内容的完全访问权限;self仍在引用您在分叉之前拥有的相同对象。您的操作系统会处理那里的详细信息,例如确保文件描述符是独立的,并且子进程获取正在更改的内存块的副本。

无论哪种方式,您对实例所做的进一步更改对父流程都不可见,除非您显式使用设计为共享的数据结构。

最新更新