Python 24/7运行应用YAML文件出现NUL字符的原因求助
多实例并发写入导致YAML文件出现NUL字符的问题分析与解决
核心成因
- 并发写入冲突:你怀疑的多实例同时操作文件是最可能的诱因。用
'a'模式打开文件时,多个进程共享文件偏移指针,但yaml.dump并非原子操作——它会分批次序列化并写入数据。当两个进程同时执行写入,很可能出现进程A刚写一部分,进程B的写入打乱了文件指针,导致内核写入空字节(NUL)填充文件块,416个NUL就是这种填充的结果。 - YAML序列化非原子性:
yaml.dump处理列表时,会逐个元素序列化写入,不是一次性把整个列表写入文件。这种分段操作在并发场景下极易被打断,造成内容损坏。 - 文件系统IO异常:如果运行环境的磁盘IO临时阻塞、缓存同步出错,也可能导致写入不完整,但结合“两周后出现”的周期,多实例并发的概率远高于这个。
验证手段
- 排查启动日志:翻查应用的启动记录,看是否存在同一时间点重复启动的日志条目,这能直接确认多实例是否存在。
- 模拟并发测试:写个简单脚本模拟多进程写入,大概率能复现问题。示例代码:
import yaml import multiprocessing import time def concurrent_write(): file_path = 'test_demo.yaml' test_data = [{'timestamp': time.time(), 'content': 'sample'}] for _ in range(100): with open(file_path, 'a') as f: yaml.dump(test_data, f) time.sleep(0.05) if __name__ == '__main__': procs = [multiprocessing.Process(target=concurrent_write) for _ in range(8)] [p.start() for p in procs] [p.join() for p in procs]
运行后打开test_demo.yaml,很大概率能看到NUL字符或乱码内容。
修复方案
- 添加文件锁:用独占锁确保同一时间只有一个进程能写入文件,可借助
filelock库简化操作:
from filelock import FileLock lock_file = f"{file_path}.lock" with FileLock(lock_file): with open(file_path, 'a') as f: yaml.dump(summary_list, f)
- 原子写入替换:先把内容写到临时文件,完成后再替换原文件,这个替换操作在多数文件系统是原子的,不会出现中途损坏:
import os import tempfile # 写入临时文件 with tempfile.NamedTemporaryFile(mode='w', delete=False, dir=os.path.dirname(file_path)) as tmp_f: yaml.dump(summary_list, tmp_f) # 原子替换原文件 os.replace(tmp_f.name, file_path)
- 防止多实例启动:应用启动时创建PID文件,检查文件是否存在且对应进程存活,避免重复启动:
import os import psutil pid_file = 'app.pid' if os.path.exists(pid_file): with open(pid_file, 'r') as f: pid = int(f.read().strip()) if psutil.pid_exists(pid): print("应用已在运行,退出") exit(1) # 写入当前PID with open(pid_file, 'w') as f: f.write(str(os.getpid()))
内容的提问来源于stack exchange,提问作者John son
相关产品推荐
相关产品推荐

