如何使 multiprocessing.Array 进程在 python 中安全

How to make a multiprocessing.Array process safe in python

在构建 multiprocessing.Array 时,构造函数接受一个参数 lock。默认设置为 True

据我了解,当 lock 标志设置为 True 时,由此创建的 multiprocessing.Array 应该是进程安全的。但是,我无法验证该行为。

我正在使用以下代码片段来验证行为:

import multiprocessing
def withdraw(balance):
    for _ in range(10000):
        balance[0] = balance[0] - 1  
def deposit(balance):    
    for _ in range(10000):
        balance[0] = balance[0] + 1
balance = multiprocessing.Array('f',[1000],lock=True) ### Notice lock=True passed explicitly
p1 = multiprocessing.Process(target=withdraw, args=(balance,))
p2 = multiprocessing.Process(target=deposit, args=(balance,))
p1.start()
p2.start()
p1.join()
p2.join()
print("Final balance = {}".format(balance[0]))

每次我 运行 此代码时,由于竞争条件影响 运行,我都会看到不同的最终结果。

你能帮我理解我在做什么吗and/or理解错了。根据我的理解,我发布的代码片段应该始终打印 1000

锁并不像你想象的那么原子。它只包装每个单独的读取或写入。我估计,在读取当前值和写入新值之间的间隙中,另一个进程已经跳入并保存了一个新值。保存此更改时,这些更改将被破坏。

有一篇针对 Multiprocessing.Value 的注释,它很有见地...

如果您将读取和写入都绑定到单个事务中,并使用所描述的 get_lock(),它将满足您的期望...

def deposit(balance):
    for _ in range(10000):
        with balance.get_lock():
            balance[0] = balance[0] + 1


def withdraw(balance):
    for _ in range(10000):
        with balance.get_lock():
            balance[0] = balance[0] - 1

为了好玩和理解,您可以将 for 循环包裹在锁中并观察它按顺序执行 所有 取款,然后释放锁并执行 全部 存款依次为:

def withdraw(balance):
    with balance.get_lock():
        for _ in range(1, 1001):
            balance[0] = balance[0] - 1
            sys.stdout.write(f'w {balance[0]}\n')