Python多处理不确定(Manager)?

时间:2011-07-15 12:20:52

标签: python multiprocessing

我正试图通过Manager界面分享一个字典,结果似乎有所不同!有时它是{1: 8, 2: 3, 3: 2, 4: 1},有时是{1: 6, 2: 3, 3: 2, 4: 1}{1: 7, 2: 3, 3: 2, 4: 1}等。这只是计算除数,应该确定性地工作......

代码在这里:

from multiprocessing import Process,  Manager
def div(x,d):
    for i in range(1,x):
        if x%i == 0:
            try:
                d[i] +=1
            except:
                d[i]=1

mgr = Manager()
d = mgr.dict()
w = [Process(target=div,args=(i,d)) for i in range(1,10)]

for k in w:
    k.start()
for k in w:
    k.join()

print d

1 个答案:

答案 0 :(得分:4)

您的代码中有一个race condition,就在这里:

                        try:
                                d[i] += 1
                        except:
                                d[i] = 1

如果d[i]尚不存在且两个进程几乎同时到达d[i] += 1,请考虑会发生什么。两者都将抛出异常,两者都将执行d[i] = 1。最终结果:d[i]1而不是2。你已经失去了增量!

经过仔细检查,即使单独d[i] += 1也可能不是原子的,因此对竞争条件开放。在内部,d[i] += 1按以下操作顺序执行:

  • 获取索引i的值;
  • 增加值;
  • 在索引i设置值。

这三个操作中的每一个都是原子的和正确的,但似乎没有任何东西可以保证整个序列的原子性。如果两个进程同时尝试对同一个d[i] += 1执行i,其中一个增量可能会因为我上面解释的原因而丢失。

使用共享字典的另一种方法是为每个进程维护自己的一组计数,并在最后聚合这些集合。这样就很难引入微妙的错误。它还可以带来更好的性能特性,因为对进程间通信的需求会减少。