使用 json 文件时,多处理锁不会阻止竞争条件

multiprocessing lock doesnt prevent race condition when working with json file

我有一个 json 文件,其中只有一个对象:

incme.json:

{
    "value": 0
}

我正在尝试使用 multiprocessingProcessPoolExecutor 来更新它,并使用 multiprocessing.Lock:

来防止竞争条件
from concurrent.futures import ProcessPoolExecutor
import multiprocessing as mp
import numpy as np
import json

def inc(tup):   
    lock, ignoreme = tup
    with lock:
        with open('incme.json', 'r') as f:
            data = json.load(f)
    print (data)
    data['value'] += 1
    with lock:
        with open('incme.json', 'w') as f:
            json.dump(data, fp=f, indent=4)
    ignoreme += 1
        
if __name__ == '__main__':
    m = mp.Manager()
    lock = m.Lock()
    
    NUMBER_OF_CPUS = mp.cpu_count()
    # use up to +++ of the cpu`s available 
    USE_UP_TO = 0.5
    
    inc((lock, 1))
    
    with ProcessPoolExecutor(max_workers=np.uint16(NUMBER_OF_CPUS * USE_UP_TO)) as executor:
        for i in range(100):    
            print('inc:')
            executor.submit(inc, ((lock, 1)))

当上面的代码运行时,它会使 value 成为 44 或低于 101.

以这种方式使用锁时:

def inc(tup):   
    lock, ignoreme = tup
    with lock:
        with open('incme.json', 'r') as f:
            data = json.load(f)
        print (data)
       data['value'] += 1
        with open('incme.json', 'w') as f:
            json.dump(data, fp=f, indent=4)
    ignoreme += 1

value 变成了 101 但现在它不能异步工作。 是什么原因造成的?跟IO相关的任务有关系吗?

你的锁似乎保护的太少了。是的,您以原子方式读取,并且您以原子方式写入,但是您 而不是 以原子方式执行读取-增量-写入序列。没有什么,例如,防止所有 100 个进程读取 0,然后每个进程将 1 加到 0,然后每个进程写出 1 作为新值。

相反,尝试删除第二个 with lock: 语句,并缩进 print() 和增量语句,以便原子地完成整个读取-增量-写入序列。

编辑

糟糕!我现在看到你已经尝试过了,并且已经发现它有效。因此,我对您为什么认为原始方式“应该”起作用感到困惑。显然不应该 ;-)