You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:44:16