Python多进程不确定性(管理器)?

1 投票
1 回答
545 浏览
提问于 2025-04-16 21:36

我正在尝试通过 Manager 接口共享一个字典(dict),但结果似乎不太一致!有时候得到的是 {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 个回答

4

你的代码中有一个叫做竞争条件的问题,就在这里:

                        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

这三步操作每一步都是独立且正确的,但没有任何东西能保证这整个过程是原子性的。如果两个进程同时尝试对同一个 i 执行 d[i] += 1,就可能会因为我刚才说的原因,导致其中一个加法操作丢失。

一个解决方案是让每个进程维护自己的一组计数,而不是使用共享的字典,最后再把这些计数汇总起来。这样就更难引入一些微妙的错误。同时,这也可能提高性能,因为进程之间的通信会减少。

撰写回答