2017-10-05 68 views
0

我的Python无限循环检测行动,运行的线程 - Python的下一个功能。每个线程都使用SQLalchemy对象来操作(同一个)MySQL数据库。这些线程开始于几个小时甚至几天的时间,或者一次开始几个 - 取决于用户的活动。 什么是/应该是使用DB最佳方式?他们都可以使用相同的全局数据库对象,或者他们每个人都应该创建新的数据库对象?Python中,螺纹,SQLAlchemy的

回答

0

请注意,SQLAlchemy的会话/连接不是线程安全

Session对象完全设计为以非并发方式使用,这在多线程方面意味着“一次只能在一个线程中”。

简而言之,每个会话都有一个后备存储以跟踪在会话中添加/删除/修改的所有对象(模型实例)。共享会话,因为你不能保证线程安全跨线程的跟踪对象不会玩这个后备存储好的。

您可以使用scoped_session提供会话对象scoped management(以及底层连接池)。通过这种方式,您的会话将绑定到Thread Local Scope,并且您可以在线程化操作中使用单个会话,而无需担心并发性。

我们称这个概念线程为本地存储,这意味着使用了一个特殊的对象,它将为每个应用程序线程维护一个独特的对象。 Python通过threading.local()构造提供了这个功能。

scoped_session使用theading.local()作为存储,并且当一个线程的范围内时称为单session被维持。来自不同线索的呼叫者将获得与scoped_session不同的session对象。

from sqlalchemy.orm import scoped_session 
from sqlalchemy.orm import sessionmaker 

# Note that session_factory, some_engine, 
# and scoped_session are global objects 
session_factory = sessionmaker(bind=some_engine) 
Session = scoped_session(session_factory) 

# Calls to `Session` will return a `session` object 
# that is backed by a thread-local store 
some_session = Session() 

# Somewhere down the line you call `Session` again 
# within the same thread will yield the same session object 

some_other_session = Session() 
some_session is some_other_session # True 

以上,some_session是会议,这是我们现在可以用交谈的数据库的一个实例。同样的Session也存在于我们创建的scoped_session注册表中。如果我们呼吁注册表中的第二次,我们得到相同的会话:

# All objects managed by `some_session` is stored in thread-local 
some_session.add(..) 
some_session.remove(..) 
some_session.query(..) 
some_session.commit() # or .rollback() 

# Calling `Session.remove()` closes `some_session` 
# and returns the `connection` back to the pool for reuse 
Session.remove() 

调用Session.remove()(这里会话是scoped_session),而不是仅仅some_session.close()是很重要的。这具有清理工作的效果。

的scoped_session.remove()方法首先调用Session.close()上的当前会话,其具有第一释放由会话所拥有的任何连接/交易资源,则丢弃所述会话本身的效果。这里的“释放”意味着连接返回到其连接池,并且任何事务状态都会回滚,最终使用底层DBAPI连接的rollback()方法。

+0

谢谢你的回答。我不清楚为什么在每个新线程中为数据库创建新对象都是不安全的......我想,当许多线程(以及它是数据库对象)同时存在时它可能会出现问题,但它与线程本地作用域 - 不是吗?[scoped_session是通过调用它来构造的,并将其传递给一个可以创建新的Session对象的工厂]。为什么简单地在线程中创建新的对象更糟? – WikS

+0

请参阅我的扩展答案。另外,还不清楚'DB'的意思。在一个线程应用程序中,'engine'和连接池是线程安全的。但是,您应该利用'scoped_session'来以线程安全的方式管理每个线程中新会话对象的创建,并且还可以管理连接池。 –

+0

我想你基本上可以为每个线程重新创建整个堆栈(引擎,连接,会话工厂),并将所有内容都视为孤岛,但是你错过了连接池的好处。 –