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
。列表实现无法自动确保代码中实现的操作序列的原子性。请记住,人际交往技能和沟通对于成为成功的程序员非常重要