写入模块开了 8 个线程,每个线程都 flock 同一路径,返回值全是 0。文件里还是出现两条互相覆盖的记录,锁像是根本没起作用。乍看像缓存或者权限的锅,追下去往往不是。
import fcntl, threading
local_lock = threading.Lock()
with local_lock, open(path, 'a') as f:
fcntl.flock(f, fcntl.LOCK_EX)
f.write(rec)
追下去是这么回事:flock 关联的是打开的文件描述,先 open 一次再 dup 给所有线程时,大家共用同一把锁,谁都能进。锁的粒度跟 fd 绑定,不跟线程绑定。
「flock 进程内多线程」相关的日志我一般连着看前后五分钟,单看一条报错经常判断不出是哪一步失败。验证用真实数据走一遍,测试数据太干净,边界情况根本碰不到。
能分两步做的操作就别合成一步,中间看一眼返回值,出问题好判断。报错里带路径的,先去看那个路径在不在、权限对不对。
具体做法是,每个线程自己 open 一次 各自拿独立的 fd 再 flock;或者干脆用 threading.Lock 在进程内串行化;跨进程才需要文件锁 别拿它当线程锁用;加日志打出 fd 编号 确认不是同一个。
验收就看一点,八线程压测后文件行数等于写入次数 没有覆盖丢失。
