通过Python多处理修改对象。池:奇怪的行为
我有一个具有两个属性的对象:dict和int。当我通过multi-processing.Pool使用分叉进程修改对象时,我会用修改后的int属性返回对象,但dict没有修改。为什么呢通过Python多处理修改对象。池:奇怪的行为,python,multiprocessing,pickle,pool,Python,Multiprocessing,Pickle,Pool,我有一个具有两个属性的对象:dict和int。当我通过multi-processing.Pool使用分叉进程修改对象时,我会用修改后的int属性返回对象,但dict没有修改。为什么呢 from multiprocessing import Pool def fork(): someObject = SomeClass() for i in range(10): someObject.method(i) print("in fork, someOb
from multiprocessing import Pool
def fork():
someObject = SomeClass()
for i in range(10):
someObject.method(i)
print("in fork, someObject has dct=%s and nbr=%i" % (someObject.dct, someObject.nbr))
return someObject
def test():
pool = Pool(processes=1)
result = pool.apply(func=fork)
print("in main, someObject has dct=%s and nbr=%i" % (result.dct, result.nbr))
class SomeClass(object):
dct = {}
nbr = 0
def method(self, nbr):
self.dct[nbr]=nbr
self.nbr+=nbr
if __name__=='__main__':
test()
输出:
在fork中,someObject具有dct={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9}和nbr=45
主要来说,someObject的dct={}和nbr=45父进程的
SomeClass.dct
和SomeClass.nbt
副本与子进程不同
更新nbr
而不是dct
的原因是nbr
在执行self.nbr+=nbr
时实际上变成了一个实例变量,它被pickle并发送回父进程。但是您从未将self.dct
分配给任何对象,因此self.dct
(实际上是指SomeClass.dct
)不会被pickle
您可以通过在SomeClass
上定义\uu getstate\uuu()
来看到这一点:
class SomeClass(object):
dct = {}
nbr = 0
def method(self, nbr):
self.dct[nbr]=nbr
self.nbr+=nbr
def __getstate__(self):
res = self.__dict__
print("pickled", res)
return res
这张照片是:
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45})
in main, someObject has dct={} and nbr=45
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45, 'dct': {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}})
in main, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
通过将dct
分配给“自身”,可以强制对其进行pickle处理:
这张照片是:
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45})
in main, someObject has dct={} and nbr=45
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45, 'dct': {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}})
in main, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
父进程的
SomeClass.dct
和SomeClass.nbt
副本与子进程不同
更新nbr
而不是dct
的原因是nbr
在执行self.nbr+=nbr
时实际上变成了一个实例变量,它被pickle并发送回父进程。但是您从未将self.dct
分配给任何对象,因此self.dct
(实际上是指SomeClass.dct
)不会被pickle
您可以通过在SomeClass
上定义\uu getstate\uuu()
来看到这一点:
class SomeClass(object):
dct = {}
nbr = 0
def method(self, nbr):
self.dct[nbr]=nbr
self.nbr+=nbr
def __getstate__(self):
res = self.__dict__
print("pickled", res)
return res
这张照片是:
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45})
in main, someObject has dct={} and nbr=45
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45, 'dct': {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}})
in main, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
通过将dct
分配给“自身”,可以强制对其进行pickle处理:
这张照片是:
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45})
in main, someObject has dct={} and nbr=45
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45, 'dct': {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}})
in main, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
父进程的
SomeClass.dct
和SomeClass.nbt
副本与子进程不同
更新nbr
而不是dct
的原因是nbr
在执行self.nbr+=nbr
时实际上变成了一个实例变量,它被pickle并发送回父进程。但是您从未将self.dct
分配给任何对象,因此self.dct
(实际上是指SomeClass.dct
)不会被pickle
您可以通过在SomeClass
上定义\uu getstate\uuu()
来看到这一点:
class SomeClass(object):
dct = {}
nbr = 0
def method(self, nbr):
self.dct[nbr]=nbr
self.nbr+=nbr
def __getstate__(self):
res = self.__dict__
print("pickled", res)
return res
这张照片是:
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45})
in main, someObject has dct={} and nbr=45
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45, 'dct': {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}})
in main, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
通过将dct
分配给“自身”,可以强制对其进行pickle处理:
这张照片是:
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45})
in main, someObject has dct={} and nbr=45
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45, 'dct': {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}})
in main, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
父进程的
SomeClass.dct
和SomeClass.nbt
副本与子进程不同
更新nbr
而不是dct
的原因是nbr
在执行self.nbr+=nbr
时实际上变成了一个实例变量,它被pickle并发送回父进程。但是您从未将self.dct
分配给任何对象,因此self.dct
(实际上是指SomeClass.dct
)不会被pickle
您可以通过在SomeClass
上定义\uu getstate\uuu()
来看到这一点:
class SomeClass(object):
dct = {}
nbr = 0
def method(self, nbr):
self.dct[nbr]=nbr
self.nbr+=nbr
def __getstate__(self):
res = self.__dict__
print("pickled", res)
return res
这张照片是:
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45})
in main, someObject has dct={} and nbr=45
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45, 'dct': {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}})
in main, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
通过将dct
分配给“自身”,可以强制对其进行pickle处理:
这张照片是:
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45})
in main, someObject has dct={} and nbr=45
in fork, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
('pickled', {'nbr': 45, 'dct': {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}})
in main, someObject has dct={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} and nbr=45
我找到了另一个解决办法。我没有使用
dict()
,而是使用了multiprocessing.Manager.dict()
,它按预期工作。我找到了另一种解决方案。我没有使用dict()
,而是使用了multiprocessing.Manager.dict()
,它按预期工作。我找到了另一种解决方案。我没有使用dict()
,而是使用了multiprocessing.Manager.dict()
,它按预期工作。我找到了另一种解决方案。我没有使用dict()
,而是使用了multiprocessing.Manager.dict()
,它工作正常。先生,你是最棒的。我花了几个小时试图弄明白这一点。谢谢我想了解为什么self.dct[nbr]=nbr
不“分配任何东西”。@derekvarrenself.nbr+=nbr
所做的是:1。阅读self.nbr
,2。向其添加nbr
,3。将结果分配回self.nbr
。相比之下,self.dct[nbr]=nbr
所做的是:1。读取self.dct
(它是对dict
对象的引用),2。通过将键nbr
设置为nbr
来改变dict的状态。在任何情况下,您实际上都不会将dict分配回self.dct
;你只是改变了它的状态,先生,你是最伟大的。我花了几个小时试图弄明白这一点。谢谢我想了解为什么self.dct[nbr]=nbr
不“分配任何东西”。@derekvarrenself.nbr+=nbr
所做的是:1。阅读self.nbr
,2。向其添加nbr
,3。将结果分配回self.nbr
。相比之下,self.dct[nbr]=nbr
所做的是:1。读取self.dct
(它是对dict
对象的引用),2。通过将键nbr
设置为nbr
来改变dict的状态。在任何情况下,您实际上都不会将dict分配回self.dct
;你只是改变了它的状态,先生,你是最伟大的。我花了几个小时试图弄明白这一点。谢谢我想了解为什么self.dct[nbr]=nbr
不“分配任何东西”。@derekvarrenself.nbr+=nbr
所做的是:1。阅读self.nbr
,2。向其添加nbr
,3。将结果分配回self.nbr
。相比之下,self.dct[nbr]=nbr
所做的是:1。读取self.dct
(它是对dict
对象的引用),2。通过设置键nbr改变dict的状态