2017-10-05 36 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

我想你基本上可以爲每個線程重新創建整個堆棧(引擎,連接,會話工廠),並將所有內容都視爲孤島,但是你錯過了連接池的好處。 –