Brightway 2.5是否支持同一数据库的并发修改操作?
Brightway 2.5 数据库并发修改问题解决方案
问题背景
尝试在Brightway 2.5中并行创建同一Ecoinvent数据库的新活动/交换,已设置bd.projects.read_only=False,但持续遇到database is locked或LockError,堆栈跟踪如下:
File "/Users/shantanu/repos/carbontrail-brightway/ef_module.py", line 490, in create_location_specific_activity new_activity = original_activity.copy() ^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/shantanu/anaconda3/lib/python3.11/site-packages/bw2data/project.py", line 446, in writable_project return wrapped(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/shantanu/anaconda3/lib/python3.11/site-packages/bw2data/backends/proxies.py", line 446, in copy activity.save() File "/Users/shantanu/anaconda3/lib/python3.11/site-packages/bw2data/project.py", line 446, in writable_project return wrapped(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/shantanu/anaconda3/lib/python3.11/site-packages/bw2data/backends/proxies.py", line 287, in save IndexManager(Database(self["database"]).filename).update_dataset(self._data) File "/Users/shantanu/anaconda3/lib/python3.11/site-packages/bw2data/search/indices.py", line 50, in update_dataset writer = self.get().writer() ^^^^^^^^^^^^^^^^^^^ File "/Users/shantanu/anaconda3/lib/python3.11/site-packages/whoosh/index.py", line 464, in writer return SegmentWriter(self, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/shantanu/anaconda3/lib/python3.11/site-packages/whoosh/writing.py", line 515, in __init__ raise LockError whoosh.index.LockError
核心结论
Brightway 2.x不支持同一数据库的并发写入操作,原因如下:
- 搜索索引依赖Whoosh库,Whoosh的索引写操作采用排他锁机制,同一时间仅允许一个写进程/线程;
- 默认数据库后端使用SQLite,SQLite的写操作同样是排他锁,无法支持多写者并发。
设置bd.projects.read_only=False仅解除项目只读限制,不改变数据库和索引的并发锁机制。
可行解决方案
优先使用批量写入:
收集所有待创建/修改的活动对象,一次性写入数据库,避免多次锁竞争。示例代码:import brightway2 as bw # 在内存中批量生成新活动 new_activities = [] for original in original_activities: new_activity = original.copy() # 执行活动修改逻辑(如设置位置、调整交换项等) new_activities.append(new_activity) # 批量写入目标数据库 bw.Database("ecoinvent").write(new_activities)这种方式仅需获取一次锁,效率远高于并行单条写入。
手动添加全局互斥锁:
若必须保留并行逻辑,需在写操作外包裹全局锁,确保同一时间仅一个进程/线程执行写操作:from multiprocessing import Lock import brightway2 as bw # 多进程场景使用跨进程锁,线程场景可替换为threading.Lock db_write_lock = Lock() def create_location_specific_activity(original_activity): with db_write_lock: new_activity = original_activity.copy() # 执行活动修改逻辑 new_activity.save()注意:多进程场景必须使用跨进程锁实现,线程锁无法跨进程生效。
数据库副本拆分(可选):
为每个并行任务创建独立的数据库副本,各自完成修改后再合并结果。此方案复杂度较高,适合大规模并行且合并成本低的场景。
内容的提问来源于stack exchange,提问作者kodr
相关产品推荐
相关产品推荐

