2017-10-05 17 views
0

My Pythonエンドレスループ検出アクション。スレッドを実行します - Pythonの次の関数です。これらのスレッドはすべて、(同じ)MySQL DB上で動作するSQLalchemyオブジェクトで使用されます。このスレッドは、何時間も何日もの間に開始されたり、一度にいくつかのスレッドが開始されたりします。ユーザーの操作に依存します。 DBを使用する最適な方法は何ですか。それらのすべてが同じグローバルdbオブジェクトを使用できますか、またはそれぞれが新しいものを作成する必要がありますか?Python、thread、SQLalchemy

答えて

0

SQLAlchemyセッション/接続がで、スレッドセーフでないことに注意してください。

セッションオブジェクトは、非同時の方法で使用されるように完全に設計されています。マルチスレッドとは、「一度に1つのスレッドのみ」を意味します。一言で言えば

、すべてのセッションは、セッション内で変更/追加/削除されたすべてのオブジェクト(モデルインスタンス)を追跡するバッキングストアを有します。共有セッションとスレッド間のオブジェクトの共有は、スレッドの安全性を保証できないため、このバッキングストアではうまくいきません。

scoped management個のセッションオブジェクト(およびその基礎となる接続プール)を提供するscoped_sessionを使用できます。このようにしてセッションは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は、私たちが今、データベースと対話するために使用できるセッションのインスタンスです。この同じセッションは、作成したscoped_sessionレジストリ内にも存在します。私たちは二度目のレジストリを要請した場合、我々は同じセッションを取り戻す:それだけではなく、some_session.close()の(scoped_sessionである、ここでセッション)Session.remove()を呼び出すことが重要である

# 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() 

。これは仕事を浄化する効果があります。

scoped_session.remove()メソッドは、最初のセッション自体を廃棄次いで、最初のセッションが所有する任意の接続/トランザクション・リソースを解放する効果を有する現在のセッション、上Session.close()を呼び出します。ここで「解放する」とは、接続が接続プールに返され、トランザクション状態がロールバックされ、最終的に基になるDBAPI接続のrollback()メソッドを使用することを意味します。

+0

ありがとうございました。なぜ私は新しいスレッドごとにDB用の新しいオブジェクトを作成するのが安全でないのか、私には明らかではない...多くのスレッド(とDBオブジェクト)が一度に存在すると問題になるかもしれないと思うが、Thread Local Scope - そうじゃない?[scoped_sessionは、新しいSessionオブジェクトを作成できるファクトリを渡して呼び出すことで構築されます。なぜ単にスレッドで新しいオブジェクトを作成するのが悪いのですか? – WikS

+0

私の拡張答えをご覧ください。また、「DB」の意味が不明です。スレッド化されたアプリケーションでは、 'engine'と接続プールはスレッドセーフです。しかし、 'scoped_session'を利用してスレッドセーフな方法で各スレッドの新しいセッションオブジェクトの作成を管理し、接続プーリングを管理するという追加の利点があります。 –

+0

私は本質的にすべてのスレッドのスタック全体(エンジン、接続、セッションファクトリ)を再作成し、サイロ内のすべてを扱うことができますが、接続プーリングのメリットは忘れてしまいます。 –