python 中 threading.lock 不能跨进程生效,应使用 multiprocessing.lock 或 filelock 库;filelock 自动适配线程 / 进程场景,将锁与文件路径强绑定,避免手动管理错误。

Python 中 threading.Lock 不能跨进程生效
如果你在多进程(multiprocessing)场景下直接复用 threading.Lock,程序不会报错,但锁完全失效——两个进程能同时写入同一个文件。这是因为 threading.Lock 只作用于当前 Python 解释器线程,不共享内存空间。
真正该用的是 multiprocessing.Lock,它底层基于系统级信号量或文件锁机制,能跨进程同步。但注意:它只保证“加锁 / 解锁”操作原子,不自动绑定到某个文件路径上——你得自己把锁和文件关联起来。
- 多线程(单进程)→ 用
threading.Lock - 多进程(含
multiprocessing.Process或concurrent.futures.ProcessPoolExecutor)→ 必须用multiprocessing.Lock - 混合场景(如主线程 + 多进程子进程)→ 锁必须由主进程创建并传入子进程,不能在子进程中新建
用 filelock 库统一处理文件读写竞争
手动管理 multiprocessing.Lock 和文件路径容易出错:比如忘记加锁、锁粒度太粗(整个程序只一个锁)、或锁对象没正确传递。更稳的方式是用 filelock ——它把锁和文件路径强绑定,且自动适配线程 / 进程场景。
安装后,FileLock 会根据运行环境自动选择 threading.Lock(单进程)或基于文件的独占锁(多进程),无需条件判断。
立即学习 “Python 免费学习笔记(深入)”;
from filelock import FileLock with FileLock("data.json.lock"): with open("data.json", "r+") as f: data = json.load(f) data["count"] += 1 f.seek(0) json.dump(data, f) f.truncate()
-
FileLock的参数是锁文件路径,不是目标文件路径;习惯上加.lock后缀 - 锁文件和目标文件最好放在同一目录,避免权限或挂载点差异导致锁失效
- Windows 下注意路径大小写不敏感,但锁文件名仍需严格一致
flock 系统调用在 Python 中的可靠替代方案
有人想直接用 Linux 的 flock 系统调用做文件锁,但在 Python 里靠 fcntl.flock 实现时,容易踩两个坑:一是锁随文件描述符关闭而自动释放(比如 with open()…… 结束后锁就丢了),二是 NFS 文件系统可能不支持 flock。
所以不建议手写 fcntl.flock,除非你明确控制文件描述符生命周期,且确认运行环境支持。更稳妥的做法是依赖 filelock(它内部在 POSIX 系统优先用 flock,失败则降级为 mkdir 原子性模拟)。
- 不要在
open()的with块内调用fcntl.flock,锁生命周期不可控 - 若必须用原生
flock,应保持 fd 打开状态,直到所有读写完成 - Docker 容器中若挂载了 host 的 NFS 卷,
flock很可能静默失效,filelock的降级逻辑此时更重要
锁的粒度与性能权衡:别让一个锁卡住所有文件操作
很多人图省事,整个应用只用一个全局锁,比如所有文件都等同一个 FileLock("global.lock")。这会导致本可并发的 I/O 操作被串行化,吞吐量骤降。
合理做法是按文件路径或业务域分锁:每个文件(或一类配置文件)对应独立锁实例。如果锁名动态生成,注意避免路径遍历或特殊字符引发冲突。
- 锁名建议哈希化:例如
FileLock(f"{hashlib.md5(path.encode()).hexdigest()}.lock") - 避免锁名含绝对路径(不同用户 / 环境路径不同),改用相对路径或业务标识符
- 日志类高频写入文件,适合用细粒度锁;而配置文件读多写少,可考虑读写锁(
readerwriterlock库)
锁本身不贵,贵的是等待。真正影响性能的从来不是锁的创建,而是谁在等、等多久——这点最容易被忽略。






























