Pet*_*ias 5 python sqlalchemy flask-sqlalchemy
由于需要处理,我想要以多线程方式生成数十个(可能数百个)数千个持久对象.
虽然对象的创建发生在单独的线程中(使用具有作用域会话的Flask-SQLAlchemy扩展btw),但是在生成完成之后,将生成的对象写入DB的调用发生在1处.
我认为,问题在于正在创建的对象是几个现有关系的一部分 - 从而触发自动添加到身份映射,尽管在单独的并发线程中创建,而在任何线程中都没有显式会话.
我希望将生成的对象包含在单个列表中,然后将整个列表(使用单个会话对象)写入数据库.这会导致如下错误:
AssertionError: A conflicting state is already present in the identity map for key (<class 'app.ModelObject'>, (1L,))
Run Code Online (Sandbox Code Playgroud)
因此,为什么我认为身份映射已经填充,因为当我尝试使用并发代码之外的全局会话添加和提交时,会触发断言错误.
最后的细节是无论什么会话对象,(范围或其他方面,因为我不完全理解如何在多线程的情况下自动添加到身份地图)我找不到方法/不知道如何获得对它们的引用,这样即使我想在每个进程中处理一个单独的会话,我也可以.
任何意见是极大的赞赏.我之前没有发布代码的唯一原因是因为很难从我的应用程序中立即抽象出一个工作示例.如果有人真的需要看到它我会发布.
每个会话都是线程本地的;换句话说,每个线程都有一个单独的会话。如果您决定将某些实例传递给另一个线程,它们将与会话“分离”。使用db.session.add_all(objects)在接收线程把他们都回来了。
出于某种原因,您似乎正在不同线程中创建具有相同标识(主键列)的对象,然后尝试将它们都发送到数据库。一种选择是解决发生这种情况的原因,以便保证身份的唯一性。您也可以尝试合并;merged_object = db.session.merge(other_object, load=False).
编辑:zzzeek 的评论让我了解了可能正在发生的其他事情:
使用 Flask-SQLAlchemy,会话与应用程序上下文相关联。由于这是线程本地的,因此生成新线程将使上下文无效;线程中将没有数据库会话。所有实例都在那里分离,无法正确跟踪关系。一种解决方案是传递app给每个线程并在with app.app_context():块内执行所有操作。在块内,首先使用db.session.add传递的实例填充本地会话。之后您仍应合并主任务以确保一致性。