多进程共享Python配置文件的锁机制实现方案咨询
解决Python进程间配置文件读写互斥问题
你提到的文件锁机制确实是解决这类跨进程资源竞争问题的最优方案,fcntl库在类Unix系统(Linux、macOS)下完全适用,它可以实现建议性文件锁——只要所有进程都遵守锁规则,就能保证读写互斥、多写排队。下面给你具体的实现方案:
核心思路
- 对于
run.py(读操作):使用共享锁(LOCK_SH),允许多个读进程同时获取锁,但会自动等待写进程释放排他锁后再执行。 - 对于
edit.py(写操作):使用排他锁(LOCK_EX),同一时间只有一个进程能持有该锁,会阻塞所有其他读/写请求,多次set_param调用也会自动排队。 - 注意:锁和文件句柄绑定,必须保持文件句柄打开直到锁释放;借助
with语句可以自动管理锁的释放,避免死锁。
修改后的run.py代码
import configparser import time import fcntl def read_config(): parser = configparser.ConfigParser() # 打开文件并保持句柄,用于加锁 with open('config.ini', 'r') as f: # 获取共享锁,阻塞模式(自动等待锁释放) fcntl.flock(f, fcntl.LOCK_SH) parser.read_file(f) # 锁会在with块结束时随文件句柄关闭自动释放 return parser while True: config = read_config() # 这里添加你使用配置的业务逻辑,比如打印参数 print("当前读取的配置:", dict(config["DEFAULT"])) time.sleep(60)
修改后的edit.py代码
import configparser import fcntl class ConfigEditor: def set_param(self, section, param, new_value): parser = configparser.ConfigParser() # 以r+模式打开,同时支持读写,全程保持句柄加锁 with open('config.ini', 'r+') as f: # 获取排他锁,阻塞直到锁可用 fcntl.flock(f, fcntl.LOCK_EX) # 读取现有配置 parser.read_file(f) # 处理不存在的section if section not in parser: parser[section] = {} # 修改参数 parser[section][param] = new_value # 重置文件指针并截断,避免残留旧内容 f.seek(0) f.truncate() # 写入新配置 parser.write(f) # 锁在with块结束时自动释放 # 测试示例 if __name__ == "__main__": editor = ConfigEditor() editor.set_param("DEFAULT", "interval", "30")
关键细节说明
- 锁的参数选择:
- 如果需要非阻塞模式(获取不到锁直接返回,不等待),可以添加
LOCK_NB参数,比如fcntl.LOCK_EX | fcntl.LOCK_NB,这时获取锁失败会抛出异常,你可以自行实现重试逻辑。
- 如果需要非阻塞模式(获取不到锁直接返回,不等待),可以添加
- 跨平台兼容方案:
fcntl是类Unix专属库,Windows系统可以用msvcrt库的locking函数,或者更简便的跨平台第三方库portalocker。用portalocker的话,锁的代码可以替换成:from portalocker import Lock, LOCK_SH, LOCK_EX # run.py读锁示例 with open('config.ini', 'r') as f: with Lock(f, LOCK_SH): parser.read_file(f) # edit.py写锁示例 with open('config.ini', 'r+') as f: with Lock(f, LOCK_EX): parser.read_file(f) # ... 修改并写入逻辑
- 异常与死锁防护:
- 如果进程持有锁时意外崩溃,系统会自动释放锁,不会造成永久死锁;建议在实际业务代码中添加
try-except块,处理文件读写、锁获取时的异常,提升稳定性。
- 如果进程持有锁时意外崩溃,系统会自动释放锁,不会造成永久死锁;建议在实际业务代码中添加
这样修改后,就能完全满足你的两个要求:run.py会等待edit.py的写操作完成后再读取,多次set_param调用也会有序执行,不会产生冲突。
内容的提问来源于stack exchange,提问作者Donbeo
相关产品推荐
相关产品推荐

