跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

多进程追加写文件时如何使用 fcntl.flock 实现文件锁

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

相关文章