我尝试从主进程和进程访问多处理管理器dict。 我重写了一个值,并添加了一个值
最后,对于键2的值,dict应为61。 对于键1,它应该包含122个字符,因为我在dict的每个acess中添加了两个字符
我得到的是键1的字符数和键2的值总是不同的。 有时,他们是122和61预期。 尽管incre.*的print语句的总和总是应该是61
我试图将md1 dict传递给进程和函数,结果是一样的。 当我将trd.daemon更改为False时,结果也是一样的
我错过了什么
代码:
import multiprocessing as mp
def local_func():
md1[1] += 'DR'
md1['2'] += 1
print('incre func')
def test_func_proc(idd):
md1[1] += idd
md1['2'] += 1
print('incre proc')
if __name__ == '__main__':
mn = mp.Manager()
md1 = mn.dict()
md1[1] = ''
md1['2'] = 1
pc = 0
procs = []
for x in range(20):
pc = pc + 1
idd = str(pc).zfill(2)
trd = mp.Process(target = test_func_proc, args=[idd, ])
trd.daemon = True
trd.start()
procs.append(trd)
md1[1] += 'TU'
md1['2'] += 1
print('incre loop')
local_func()
md1[1] += 'CX'
md1['2'] += 1
print('incre main')
while True:
end = True
for proc in procs:
if proc.is_alive():
end = False
if end is True:
break
print('md1 %s' % md1)
你错过了什么?像
md1[1] += 'TU'
和md1['2'] += 1
这样的操作不是原子的。特别是,要执行md1[1] += 'TU'
,即附加到一个在Python中不可变的字符串,解释器必须首先获取旧字符串,然后创建一个新的字符串,它是旧字符串和'TU'
的串联,最后存储结果。这可以在多个进程中并行进行,最后一个存储结果的进程可以覆盖在不同进程中创建的结果上。因此,您需要确保一旦一个进程启动了fetch-concatenate-store系列操作,就不会有其他进程同时对同一字符串执行相同的操作(或整数增量操作)。确保序列化的唯一方法是使用Lock
考虑到函数
test_func_proc
是100%CPU(调试打印语句除外),我建议不要盲目地在一台CPU核数较少的计算机上创建20个进程,而应该创建一个处理池,其大小受实际拥有的CPU核数的限制。但是Lock
不能作为参数传递给辅助函数。相反,池中的每个进程将Lock
实例视为一个全局变量,该变量已使用特殊的池初始值设定项函数初始化印刷品:
更新
阅读关于Augmented Assignment Statements的文档,其中部分说明(但您应该阅读整个部分):
以及一个分解Python代码的演示,以揭示
+=
运算符的非原子性(执行b += 1
需要4条指令):问题在于,两个进程可以同时执行8到14的指令,加载相同的
b
值并将b
增加到相同的新值。您需要确保一次只能有一个进程执行从8到14的指令。相关问题 更多 >
编程相关推荐