「Pythonマルチプロセッシングまたはos.fork()でエンジン/接続/セッションを使用するにはどうすればよいですか?」追加の強調:
SQLAlchemy Engineオブジェクトは、既存のデータベース接続の接続プールを参照します。したがって、このオブジェクトが子プロセスに複製される場合、目標はデータベース接続が引き継がれないようにすることです 。
および
ただし、トランザクションがアクティブなセッションまたは接続が共有されている場合、これに対する自動修正はありません。アプリケーションは、新しい子プロセスが新しいConnectionオブジェクトとトランザクション、およびORMSessionオブジェクトのみを開始するようにする必要があります。
この問題は、ライブのグローバル session
を継承するフォークされた子プロセスに起因します。 、 Connection
を保持しています 。 target
の場合 init
を呼び出します 、 engine
へのグローバル参照を上書きします およびsession
、したがって、子のrefcountを0に減らし、強制的に終了させます。たとえば、何らかの方法で子の継承されたセッションへの別の参照を作成する場合、それがクリーンアップされるのを防ぎますが、そうしないでください。 main
の後 が参加し、通常どおりビジネスに復帰しました。これは、現在ファイナライズされている可能性のある、または同期していない接続を使用しようとしています。何回か繰り返した後にのみエラーが発生する理由については、よくわかりません。
グローバルを使用してこの状況を処理する唯一の方法は、
です。- すべてのセッションを閉じる
-
engine.dispose()
を呼び出します
フォークする前に。これにより、接続が子に漏れるのを防ぐことができます。例:
def main():
global session
init()
try:
dummy = Dummy(value=1)
session.add(dummy)
session.commit()
dummy_id = dummy.id
# Return the Connection to the pool
session.close()
# Dispose of it!
engine.dispose()
# ...or call your cleanup() function, which does the same
p = multiprocessing.Process(target=target, args=(dummy_id,))
p.start()
p.join()
# Start a new session
session = Session()
dummy = session.query(Dummy).get(dummy_id)
assert dummy.value == 2
finally:
cleanup()
2番目の例は子のファイナライズをトリガーしないため、機能しているように見えますが、最初の例と同じように壊れている可能性があります。これは、セッションのコピーと、main<でローカルに定義された接続を引き続き継承しているためです。 / code> 。