LockFile简要分析
FileLock
是 Python 中用于实现文件级锁定的工具(来自 filelock
库),专门解决多进程/多线程环境下对共享资源(如文件)的并发访问问题。以下是它在当前代码中的 核心作用 和 详细工作机制:
1. 为什么需要 FileLock?
- 问题场景:当多个进程同时运行
Expr2Vec_api
时,可能会同时读写同一个缓存文件bgem3.json
,导致: - 数据损坏:多个进程同时写入文件时,内容可能被覆盖或混合。
- 脏读:一个进程正在写入时,另一个进程读取到不完整的中间状态。
- 解决方案:
FileLock
通过创建一个临时锁文件(bgem3.json.lock
)实现互斥访问,确保同一时间只有一个进程能操作文件。
2. FileLock 的工作流程
(1) 锁的创建
lock_file = cache_file + ".lock"# 锁文件路径(如 bgem3.json.lock)
with FileLock(lock_file):
# 临界区代码(读写文件)
- 当进入
with
块时:
- 尝试创建
lock_file
(若已存在则阻塞等待)。 - 锁文件存在期间,其他进程的
FileLock
会检测到锁并等待。
(2) 文件操作的安全性
- 读缓存时:
with FileLock(lock_file):
if os.path.exists(cache_file):
with open(cache_file, 'r') as f:
cache = json.load(f)
-
其他进程无法修改文件,直到当前进程释放锁(退出
with
块)。 -
写缓存时:
with FileLock(lock_file):
with open(cache_file, 'w') as f:
json.dump(updated_cache, f)
- 写入时独占文件,避免其他进程同时写入导致数据损坏。
(3) 锁的释放
- 退出
with
块时,自动删除lock_file
,允许其他进程获取锁。
3. 关键特性
特性 | 说明 |
---|---|
跨进程安全 | 适用于多进程环境(而 threading.Lock 仅限同一进程内)。 |
阻塞机制 | 默认阻塞直到锁可用(可通过 timeout 参数设置超时)。 |
原子性操作 | 锁文件创建是原子操作,避免竞态条件。 |
兼容性 | 在 Unix/Windows 上均有效(依赖文件系统特性)。 |
4. 对比其他锁方案
方案 | 缺点 | FileLock 优势 |
---|---|---|
threading.Lock | 仅限同一进程的线程间同步。 | 支持跨进程。 |
fcntl.flock | Windows 不支持。 | 跨平台。 |
手动创建锁文件 | 需要处理异常和清理,易出错。 | 自动管理锁生命周期。 |
5. 在代码中的实际意义
- 缓存一致性:确保所有进程看到的
bgem3.json
是完整版本,避免: - 丢失新增的
new_cache
数据。 - 读取到部分写入的损坏 JSON。
- 性能权衡:虽然锁会引入短暂等待,但避免了 API 重复调用(网络开销远大于文件锁开销)。
6. 扩展建议
- 锁超时:可添加
timeout
避免死锁:
with FileLock(lock_file, timeout=10):# 最多等待10秒
- 异常处理:捕获
Timeout
异常并回退:
try:
with FileLock(lock_file, timeout=5):
# 操作文件
except Timeout:
print("无法获取锁,直接调用API")
return uncached_vecs
通过 FileLock
,代码在多进程环境下既保持了高性能(减少 API 调用),又保证了数据安全。