多进程写文件时如何使用文件锁(fcntl 或 msvcrt)
发布时间 - 2026-01-23 00:00:00 点击率:次多进程写文件错乱的根本原因是write()系统调用在无同步机制下不保证原子性,尤其超PIPE_BUF时会被拆分;Linux/macOS用fcntl.flock加文件描述符级建议锁,Windows需用msvcrt.locking实现字节范围锁。
Python 多进程写文件时为什么直接 open + write 会出错
多个进程同时 open('log.txt', 'a') 并调用

write(),看似安全,实际常出现内容错乱、覆盖、甚至部分写入丢失。根本原因不是 Python 层面的 GIL(多进程绕过 GIL),而是底层系统调用 write() 在没有同步机制时,对同一文件描述符的并发操作不保证原子性——尤其当写入量超过 PIPE_BUF(通常 4KB)时,write() 可能被拆成多次系统调用,中间插入其他进程的写入。
Linux/macOS 下用 fcntl.flock 实现进程级文件锁
flock() 是最常用、语义清晰的方案,它基于内核维护的 advisory lock(建议锁),要求所有参与者主动调用加锁/解锁,不强制拦截非法写入,但足够可靠。
- 锁是文件描述符粒度的,不是文件路径粒度:必须在
open()后对返回的fd加锁,且子进程继承 fd 时锁状态可能变化(默认不继承,需设FD_CLOEXEC=0才可跨 fork 传递) - 使用
flock(fd, fcntl.LOCK_EX)加排他锁,写完后flock(fd, fcntl.LOCK_UN)解锁;推荐配合try/finally或上下文管理器 - 不要对已关闭的 fd 调用
flock(),会报OSError: [Errno 9] Bad file descriptor - 示例片段:
import fcntl import os
fd = os.open('data.txt', os.O_RDWR | os.O_CREAT) try: fcntl.flock(fd, fcntl.LOCK_EX) os.lseek(fd, 0, os.SEEK_END) os.write(fd, b'new line\n') finally: fcntl.flock(fd, fcntl.LOCK_UN) os.close(fd)
Windows 下必须用 msvcrt.locking 替代 flock
Windows 不支持 flock(),且其 open() 返回的文件对象不提供原生锁接口。唯一可移植的底层方案是 msvcrt.locking(),但它只作用于已打开的文件对象的字节区域,且仅限于普通磁盘文件(不支持管道、设备等)。
- 必须用
os.open()获取原始 fd,再用os.fdopen(fd, 'r+b')包装为文件对象,否则msvcrt.locking()会失败 - 锁定范围需明确指定字节偏移和长度,例如锁定整个文件可传
0偏移 +1字节长度(因 Windows 的 lock 是“字节范围锁”,最小单位是 1 字节,且锁任意一字节即阻塞对该文件全部写入) - 调用前确保文件已存在且可写,否则
locking()抛IOError: No locks available - 示例关键步骤:
import os import msvcrt
fd = os.open('log.txt', os.O_RDWR | os.O_CREAT) try:
锁定第 0 字节(效果等同锁整个文件)
msvcrt.locking(fd, msvcrt.LK_NBLCK, 1) # 非阻塞,失败抛异常 os.lseek(fd, 0, os.SEEK_END) os.write(fd, b'win log\n')
finally: msvcrt.locking(fd, msvcrt.LK_UNLCK, 1) os.close(fd)
跨平台封装要注意的三个坑
真正落地时,不能简单 if-else 切换锁模块,还要处理:
-
fcntl和msvcrt的异常类型不同:flock()抛OSError,locking()抛IOError(Py3 中已继承自OSError,但仍需统一捕获) - Windows 下
LOCK_NB对应msvcrt.LK_NBLCK,但 Linux 的LOCK_NB是 flag,需与LOCK_EX按位或;而 Windows 是独立常量 - 最容易被忽略的是:锁只对「通过该 fd 写入」起作用;如果某进程绕过锁、直接用
open(..., 'a').write(),锁完全无效——advisory lock 的本质就是靠自觉
文件锁不是银弹,它解决的是“多个进程协调写同一文件”的问题,而不是替代日志轮转、队列分发等更高层设计。真要高频写共享文件,优先考虑用 multiprocessing.Queue 或临时文件 + 原子重命名。
# linux
# python
# windows
# 字节
# mac
# ai
# macos
# win
# cos
# 同步机制
# 为什么
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
linux top下的 minerd 木马清除方法
Laravel如何实现用户注册和登录?(Auth脚手架指南)
如何确保西部建站助手FTP传输的安全性?
开心动漫网站制作软件下载,十分开心动画为何停播?
常州企业网站制作公司,全国继续教育网怎么登录?
百度输入法全感官ai怎么关 百度输入法全感官皮肤关闭
Python自然语言搜索引擎项目教程_倒排索引查询优化案例
Laravel Telescope怎么调试_使用Laravel Telescope进行应用监控与调试
黑客如何利用漏洞与弱口令入侵网站服务器?
如何破解联通资金短缺导致的基站建设难题?
html5怎么画眼睛_HT5用Canvas或SVG画眼球瞳孔加JS控制动态【绘制】
微信小程序 wx.uploadFile无法上传解决办法
Java遍历集合的三种方式
node.js报错:Cannot find module 'ejs'的解决办法
Laravel怎么做缓存_Laravel Cache系统提升应用速度的策略与技巧
Python结构化数据采集_字段抽取解析【教程】
Laravel如何实现一对一模型关联?(Eloquent示例)
奇安信“盘古石”团队突破 iOS 26.1 提权
如何用已有域名快速搭建网站?
Linux系统命令中screen命令详解
php在windows下怎么调试_phpwindows环境调试操作说明【操作】
香港服务器网站推广:SEO优化与外贸独立站搭建策略
Laravel如何使用Facades(门面)及其工作原理_Laravel门面模式与底层机制
Android利用动画实现背景逐渐变暗
怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?
北京网页设计制作网站有哪些,继续教育自动播放怎么设置?
如何快速重置建站主机并恢复默认配置?
佐糖AI抠图怎样调整抠图精度_佐糖AI精度调整与放大细化操作【攻略】
南京网站制作费用,南京远驱官方网站?
香港服务器WordPress建站指南:SEO优化与高效部署策略
儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?
javascript中的try catch异常捕获机制用法分析
厦门模型网站设计制作公司,厦门航空飞机模型掉色怎么办?
中山网站制作网页,中山新生登记系统登记流程?
如何在景安服务器上快速搭建个人网站?
如何在 Telegram Web View(iOS)中防止键盘遮挡底部输入框
在线教育网站制作平台,山西立德教育官网?
如何有效防御Web建站篡改攻击?
JavaScript中如何操作剪贴板_ClipboardAPI怎么用
如何快速选择适合个人网站的云服务器配置?
如何快速上传建站程序避免常见错误?
Laravel如何使用.env文件管理环境变量?(最佳实践)
Laravel如何优雅地处理服务层_在Laravel中使用Service层和Repository层
Laravel如何实现登录错误次数限制_Laravel自带LoginThrottles限流配置【方法】
长沙企业网站制作哪家好,长沙水业集团官方网站?
Laravel如何集成第三方登录_Laravel Socialite实现微信QQ微博登录
想要更高端的建设网站,这些原则一定要坚持!
如何快速搭建高效WAP手机网站吸引移动用户?
高端建站三要素:定制模板、企业官网与响应式设计优化
制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?

