fcntl.flock不能跨进程保护追加写,因O_APPEND使内核自动seek到末尾再write,而flock锁的是fd而非追加行为本身,导致多进程write仍可能重叠;正确做法是用os.open获取fd、加锁、seek(0,2)、write、flush、解锁。
为什么 fcntl.flock 不能跨进程保护追加写(a 模式)
直接用
锁住一个以
模式打开的文件对象,**并不能阻止其他进程同时写入**。根本原因是:Python 的
在底层调用
时带了
标志,而该标志会让内核在每次
前自动将文件偏移量移到末尾——这个动作是原子的,但
锁的是整个文件描述符,不是“追加行为”本身。两个进程同时
,可能仍会因缓冲、调度等原因导致内容重叠或换行错乱。
正确做法:先锁再 seek + write,避开 a 模式
必须放弃
模式,改用
或
打开文件,手动控制偏移量。关键步骤是:获取独占锁 →
到末尾 → 写入 → 解锁。否则锁和写之间存在竞态窗口。
必须作用于同一个打开的文件描述符(即不能在
块里锁完就关文件)
推荐用
获取原始 fd,再用
包装为文件对象,避免 Python 缓冲干扰
务必使用
配合异常捕获,防止死等
常见错误:用 with open() + flock 混用
下面这段代码看似合理,实则无效:
问题在于:
退出时会自动
,而
是 fd 级锁,
后锁立即释放;且
模式的
虽原子,但多个进程仍可能在
和
之间插入写操作。
Trae win
Trae Windows 官方版本现已全面支持 Win10 和 Win11 系统(64位)。国内开发者可直接访问 Trae 中文官网(trae.cn 或 trae.com.cn),一键下载官方正版 .exe 安装包,享受国内直连的高速稳定体验。安装过程极其简便,双击即可运行,并支持一键无缝导入 VS Code 或 Cursor 的原有主题、快捷键及插件配置。登录支持手机号、微信或稀土掘金账号。内置免费的豆包与 DeepSeek 等顶级大模型,让你开箱即用,轻松开启高效的 AI 智能编程之旅。
下载
不要对
返回的文件对象加锁后还依赖其上下文管理
不要在
模式下幻想
能串行化写入
日志类场景建议用
或专用日志库,它们内部已处理锁与追加逻辑
注意 fcntl.flock 的平台限制和替代方案
在 Linux/
mac
OS 上工作正常,但在 NFS 文件系统上可能不生效;Windows 完全不支持
,需改用
或
+ 信号量。如果目标环境不确定,优先考虑外部协调机制(如 Redis 分布式锁)或追加写专用工具(如
+ 文件重定向)。
真正棘手的不是加锁本身,而是「锁的生命周期必须严格覆盖从定位到写入再到刷盘的全过程」——漏掉
或提前
,都等于没锁。
flock'a'open('file', 'a')open(2)O_APPENDwrite(2)flockwrite'a''r+''w+'seek(0, 2)flockwith open() as f:os.open()os.fdopen()fcntl.LOCK_EX | fcntl.LOCK_NBimport fcntl
import os
fd = os.open('log.txt', os.O_RDWR | os.O_CREAT)
try:
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
with os.fdopen(fd, 'w') as f:
f.seek(0, 2) # 移动到末尾
f.write('new line\n')
f.flush() # 确保落盘
finally:
fcntl.flock(fd, fcntl.LOCK_UN)
os.close(fd)
with open('log.txt', 'a') as f:
fcntl.flock(f.fileno(), fcntl.LOCK_EX)
f.write('line\n') # ❌ 危险!'a' 模式下 write 自动 seek,但锁已释放(with 结束 close)
with open()close()flockclose()'a'writeflockwritewith open(...)'a'flockRotatingFileHandlerflockflockmsvcrt.lockingmmapteeflush()close()