Python多进程不确定性(管理器)?
我正在尝试通过 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
,就可能会因为我刚才说的原因,导致其中一个加法操作丢失。
一个解决方案是让每个进程维护自己的一组计数,而不是使用共享的字典,最后再把这些计数汇总起来。这样就更难引入一些微妙的错误。同时,这也可能提高性能,因为进程之间的通信会减少。