python multiprocessing.Process.Manager是否未生成一致的结果?
我已经编写了以下代码来说明我看到的问题。我试图使用python multiprocessing.Process.Manager是否未生成一致的结果?,python,multiprocessing,python-multiprocessing,Python,Multiprocessing,Python Multiprocessing,我已经编写了以下代码来说明我看到的问题。我试图使用Process.Manager.list()跟踪列表并增加该列表的随机索引 每次生成100个进程,每个进程将列表的随机索引增加1。因此,人们希望每次生成的列表的总和都是相同的,对吗?我得到203到205之间的数据 from multiprocessing import Process, Manager import random class MyProc(Process): def __init__(self, A):
Process.Manager.list()
跟踪列表并增加该列表的随机索引
每次生成100个进程,每个进程将列表的随机索引增加1。因此,人们希望每次生成的列表的总和都是相同的,对吗?我得到203到205之间的数据
from multiprocessing import Process, Manager
import random
class MyProc(Process):
def __init__(self, A):
Process.__init__(self)
self.A = A
def run(self):
i = random.randint(0, len(self.A)-1)
self.A[i] = self.A[i] + 1
if __name__ == '__main__':
procs = []
M = Manager()
a = M.list(range(15))
print('A: {0}'.format(a))
print('sum(A) = {0}'.format(sum(a)))
for i in range(100):
procs.append(MyProc(a))
map(lambda x: x.start(), procs)
map(lambda x: x.join(), procs)
print('A: {0}'.format(a))
print('sum(A) = {0}'.format(sum(a)))
答案是通过上面的评论得出的,有一个竞赛条件发生,因为下面的一行:
self.A[i] = self.A[i] + 1
实际上是两个操作,一个是
\uuuu getitem\uuuuuuuuuuuuuuuuuuuuuuu
和一个\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu setitem\uuuuuuuuuuuuuuuuuu
self.A[i] = self.A[i] + 1
实际上是两个操作,一个是\uuu getitem\uuuuuuuuuuuuuuuuuuuuuuuuuu
和一个\uuuuu setitem\uuuuuuuuuuuuuuuuuuuuuuuuu,正如米利穆斯所指出的,这里的问题是在self.a[i]=self.a[i]+1
中出现的竞争条件。当计算出self.A[i]+1
时,self.A[i]
可能已经被另一个进程更改了
解决问题的一个可能方法是将索引传递回父级,然后父级执行加法
from multiprocessing import Process, Manager
import random
class MyProc(Process):
def __init__(self, B, length):
Process.__init__(self)
self.B = B
self.length = length
def run(self):
i = random.randint(0, self.length-1)
self.B.append(i)
if __name__ == '__main__':
procs = []
M = Manager()
a = range(15)
b = M.list()
print('A: {0}'.format(a))
print('sum(A) = {0}'.format(sum(a)))
for i in range(100):
procs.append(MyProc(b, len(a)))
map(lambda x: x.start(), procs)
map(lambda x: x.join(), procs)
for i in b:
a[i] = a[i] + 1
print('A: {0}'.format(a))
print('sum(A) = {0}'.format(sum(a)))
将一个元素附加到一个数组中只是一个操作,因此避免了争用条件。正如millimoose所指出的,这里的问题是出现在self.a[i]=self.a[i]+1
中的争用条件。当计算出self.A[i]+1
时,self.A[i]
可能已经被另一个进程更改了
解决问题的一个可能方法是将索引传递回父级,然后父级执行加法
from multiprocessing import Process, Manager
import random
class MyProc(Process):
def __init__(self, B, length):
Process.__init__(self)
self.B = B
self.length = length
def run(self):
i = random.randint(0, self.length-1)
self.B.append(i)
if __name__ == '__main__':
procs = []
M = Manager()
a = range(15)
b = M.list()
print('A: {0}'.format(a))
print('sum(A) = {0}'.format(sum(a)))
for i in range(100):
procs.append(MyProc(b, len(a)))
map(lambda x: x.start(), procs)
map(lambda x: x.join(), procs)
for i in b:
a[i] = a[i] + 1
print('A: {0}'.format(a))
print('sum(A) = {0}'.format(sum(a)))
将一个元素添加到数组中只是一个操作,因此避免了竞争条件。(您没有进行任何类型的同步。这是一个非常基本的问题,“在开始编码之前浏览一下有关进程同步的大学教科书”之类的问题。)对于同步,没有“似乎基本上有效”这样的事情。有了竞争条件bug,就没有预期的bug和可预测的bug行为。还有,你从哪里得到这种印象?在列表上执行任何单个操作(例如append()
)都可能是安全的,但是self.A[i]=self.A[i]+1
显然是两个操作,一个\uu getitem\uuuuuuu
和一个\uuuuu setitem\uuuu
。列表实现无法自动确保代码中实现的一系列操作的原子性。ughhhh,还请记住,人的技能和沟通对于成为一名成功的程序员非常重要(您没有进行任何类型的同步。这是一个非常基本的问题,“在你开始编码之前,先浏览一下关于进程同步的大学教科书”之类的问题。)对于同步,没有“似乎大部分都有效”这样的东西“有了竞争条件bug,就没有预期的bug和可预测的bug行为。还有,你从哪里得到这种印象?在列表上执行任何单个操作(例如append()
)都可能是安全的,但是self.A[i]=self.A[i]+1
显然是两个操作,一个\uu getitem\uuuuuuu
和一个\uuuuu setitem\uuuu
。列表实现无法自动确保代码中实现的操作序列的原子性。请记住,人际交往技能和沟通对于成为成功的程序员非常重要