使用 json 文件时,多处理锁不会阻止竞争条件
multiprocessing lock doesnt prevent race condition when working with json file
我有一个 json
文件,其中只有一个对象:
incme.json
:
{
"value": 0
}
我正在尝试使用 multiprocessing
和 ProcessPoolExecutor
来更新它,并使用 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()
和增量语句,以便原子地完成整个读取-增量-写入序列。
编辑
糟糕!我现在看到你已经尝试过了,并且已经发现它有效。因此,我对您为什么认为原始方式“应该”起作用感到困惑。显然不应该 ;-)
我有一个 json
文件,其中只有一个对象:
incme.json
:
{
"value": 0
}
我正在尝试使用 multiprocessing
和 ProcessPoolExecutor
来更新它,并使用 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()
和增量语句,以便原子地完成整个读取-增量-写入序列。
编辑
糟糕!我现在看到你已经尝试过了,并且已经发现它有效。因此,我对您为什么认为原始方式“应该”起作用感到困惑。显然不应该 ;-)