在 class 实例中通过自身传递参数,而在 Python 中进行多处理
Pass arguments through self in class instance while multiprocessing in 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'
更具体地说,我想传递 manager.Queue() 对象,不确定是否会有所不同。
如果这是一个简单的 C fork(),因为整个过程被相同地复制 - 除了 pid -,self
将是相同的。但是 Python multiprocessing 可能正在做一些我不知道的事情,或者可能在 "don't use it like this, this may change in the future" 之类的地方出现警告。我没有找到任何专门解决这个问题的内容。
我真正担心的是 args
中传递的参数,特别是如果它们与多处理模块相关联,可能会围绕 fork() 进行转换以避免任何问题。
Python 3.6.5
对于除 fork 启动方法之外的任何其他方法,目标和参数都使用 pickling 发送到工作进程,当 Process.start()
是叫。对于fork方法,子进程是在同一个点fork的,所以当Process.start()
被调用时。
所以当你不使用fork启动方法时,你需要担心的是你的数据是否可以被pickle。如果是这种情况,则没有理由避免使用 class 实例和 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
named.
如果您使用 fork start 方法,那么子进程可以完全访问父进程内存中的所有内容; self
仍在引用您在分叉之前拥有的同一对象。您的 OS 负责那里的细节,例如确保文件描述符是独立的,以及子进程获得正在更改的内存块的副本。
无论哪种方式,除非您明确使用 data structures designed to be shared.
,否则您对实例所做的进一步更改对父进程是不可见的
似乎可以,但是分叉后使用 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'
更具体地说,我想传递 manager.Queue() 对象,不确定是否会有所不同。
如果这是一个简单的 C fork(),因为整个过程被相同地复制 - 除了 pid -,self
将是相同的。但是 Python multiprocessing 可能正在做一些我不知道的事情,或者可能在 "don't use it like this, this may change in the future" 之类的地方出现警告。我没有找到任何专门解决这个问题的内容。
我真正担心的是 args
中传递的参数,特别是如果它们与多处理模块相关联,可能会围绕 fork() 进行转换以避免任何问题。
Python 3.6.5
对于除 fork 启动方法之外的任何其他方法,目标和参数都使用 pickling 发送到工作进程,当 Process.start()
是叫。对于fork方法,子进程是在同一个点fork的,所以当Process.start()
被调用时。
所以当你不使用fork启动方法时,你需要担心的是你的数据是否可以被pickle。如果是这种情况,则没有理由避免使用 class 实例和 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
named.
如果您使用 fork start 方法,那么子进程可以完全访问父进程内存中的所有内容; self
仍在引用您在分叉之前拥有的同一对象。您的 OS 负责那里的细节,例如确保文件描述符是独立的,以及子进程获得正在更改的内存块的副本。
无论哪种方式,除非您明确使用 data structures designed to be shared.
,否则您对实例所做的进一步更改对父进程是不可见的