python - 使用 json 文件时,多处理锁不会阻止竞争条件
问题描述
我有一个json
文件,其中只有一个对象:
incme.json
:
{
"value": 0
}
我正在尝试使用multiprocessing
with更新它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()
和递增语句,以便整个读取-递增-写入序列以原子方式完成。
编辑
哎呀!我现在看到您已经尝试过了,并且已经发现它有效。所以我只是对你为什么认为原来的方式“应该”工作感到困惑。它显然不应该;-)
推荐阅读
- angular - 使用 Angular 将文件上传到 Symfony
- arrays - 将给定大小的 char 数组复制到 C 中的整数的正确方法是什么?
- html - font-face 和闪烁字体
- javascript - 当前效果100%完成后不执行回调函数
- java - NoSuchMethodError 使用 spring-boot
- spring-data-jpa - 弹簧数据 JPA JPQL 多连接实体
- mysql - org.hibernate.engine.jdbc.spi.SqlExceptionHelper:“订单子句”中的未知列“PrefId”
- azure - 使用 Azure AD B2C 的 SMS 功能
- ffmpeg - ffmpeg 只绘制最后一个文本
- java - 我如何通过 className 单击此元素,因为我将它用于具有相同类名的多个屏幕