多Python实例并行读写JSON文件锁机制异常问题排查与修正
多实例并行读写JSON文件的锁与IO问题修复
嘿,我看到你遇到的问题了——用w+模式打开文件时直接清空了内容,而且锁的用法没到位,导致JSON加载失败。咱们一步步理清楚问题出在哪,再给你修复后的代码。
首先说为什么会报错:
- 当你用
open('test.json', 'w+')的时候,Python会立刻清空整个文件内容,这时候再用json.load(open('test.json'))去读,读到的是空字符串,自然会报JSON格式无效的错误。 - 另外,你两次打开文件是完全独立的句柄:
with块里的file和后面open出来的是两个不同的对象,你给第一个加了锁,第二个根本不受影响,等于锁白加了,完全起不到同步多个实例的作用。 - 还有,你读完就释放锁了,但写入操作还没做,这时候其他实例可能会插队修改文件,导致你的写入覆盖掉别人的修改。
接下来是正确的实现思路和代码:
我们需要保证锁绑定在同一个文件句柄上,用不会清空文件的读写模式,并且在锁的保护下完成「读取最新内容→处理→写入」的完整流程。
import json import fcntl # 可选:预处理阶段,读取初始数据做一些前置操作(如果不需要可以直接跳过这部分) with open('test.json', 'r') as f: initial_data = json.load(f) # 这里写你的预处理逻辑,比如基于初始数据计算一些值 # do things with initial_data... # 核心同步读写流程 with open('test.json', 'r+') as file: # 加排他锁,阻塞等待直到拿到锁(如果需要非阻塞模式,保留LOCK_NB并处理BlockingIOError) fcntl.flock(file, fcntl.LOCK_EX) # 将文件指针移到文件开头,确保读取的是最新完整内容 file.seek(0) try: latest_data = json.load(file) except json.JSONDecodeError: # 容错处理:极端情况(比如某个实例截断文件后崩溃),默认初始化空字典 latest_data = {} # 这里写你的实际数据处理逻辑,比如更新计数 latest_data['count'] = latest_data.get('count', 0) + 1 # 准备写入:先移到文件开头,截断文件(清除旧内容,避免残留) file.seek(0) file.truncate() # 写入新数据 json.dump(latest_data, file, indent=2) # 强制刷新缓冲区,确保内容写入磁盘(避免缓存导致的同步问题) file.flush() # with块结束后文件会自动关闭,锁也会自动释放,不用手动调用LOCK_UN
再给你划几个关键要点:
- 用
r+模式代替w+:r+是读写模式,打开时不会清空文件,完美适配我们先读再写的需求。 - 全程用同一个文件句柄:锁是和文件句柄绑定的,所有读写操作都用这个句柄,才能保证锁能同步所有实例的访问。
- 加锁后再读取最新内容:这样能确保你拿到的是其他实例修改后的最新状态,不会基于旧数据做无效处理。
- 写入前截断文件:如果新数据比旧数据短,不截断的话文件末尾会残留旧内容,导致下次读取JSON解析失败。
- 容错JSON解析错误:极端场景下(比如某个实例刚截断文件就崩溃了),文件内容不完整,这时候需要默认初始化数据,避免脚本直接崩溃。
- 关于
LOCK_NB:如果你不需要非阻塞锁(也就是不想在拿不到锁的时候直接报错),就去掉它,让脚本阻塞等待锁释放,这是大多数同步场景的合理选择。
内容的提问来源于stack exchange,提问作者lo tolmencre
相关产品推荐
相关产品推荐

