マルチスレッドの Python プロセスには、多数の非デーモンスレッドがあります。これは、メイン スレッドが終了/停止した後でもメイン プロセスを維持するスレッドを意味します。
私の非デーモン スレッドは、メイン スレッド内の特定のオブジェクトへの弱参照を保持していますが、メイン スレッドが終了すると (制御がファイルの下部に落ちます)、これらのオブジェクトはガベージ コレクションされていないように見えます。火。
メインスレッドがガベージコレクションされると期待するのは間違っていますか? スレッドローカルの割り当てが解除される(つまり、ガベージコレクションが行われる)と予想していました...
私は何を逃したのですか?
サポート資料
pprint.pprint( threading.enumerate() )
メイン スレッドが停止し、他のスレッドが続行していることを示す出力。
[<_MainThread(MainThread, stopped 139664516818688)>,
<LDQServer(testLogIOWorkerThread, started 139664479889152)>,
<_Timer(Thread-18, started 139663928870656)>,
<LDQServer(debugLogIOWorkerThread, started 139664437925632)>,
<_Timer(Thread-17, started 139664463103744)>,
<_Timer(Thread-19, started 139663937263360)>,
<LDQServer(testLogIOWorkerThread, started 139664471496448)>,
<LDQServer(debugLogIOWorkerThread, started 139664446318336)>]
そして、誰かが常にユースケースについて尋ねるので...
私のネットワーク サービスは、リアルタイムの締め切りに間に合わないことがあります (最悪の場合、システム全体の障害が発生します)。これは、(重要な) DEBUG データのロギングが、ファイルシステムに癇癪を起こすたびにブロックされるためであることが判明しました。そこで、I/O のブロッキングをワーカー スレッドに任せるために、多くの確立された特殊なログ ライブラリを改造しようとしています。
悲しいことに、確立された使用パターンは、重複する並列トランザクションをログに記録する短命のロギング チャネルと、明示的に閉じられることのない長寿命のモジュール スコープ チャネルの混合です。
そこで、ワーカー スレッドへのメソッド呼び出しを延期するデコレータを作成しました。ワーカー スレッドは非デーモンであり、インタープリターが終了する前にすべての (遅い) ブロッキング I/O が完了し、クライアント側 (メソッド呼び出しがエンキューされる場所) への弱い参照を保持します。クライアント側でガベージ コレクションが行われると、弱い参照のコールバックが起動し、ワーカー スレッドはキューに追加される作業がなくなることを認識し、次の都合のよいときに終了します。
これは、ロギング チャネルがメイン スレッドにある場合という 1 つの重要なユース ケースを除いて、すべて正常に機能するようです。メイン スレッドが停止または終了すると、ロギング チャネルはファイナライズされないため、(デーモンではない) ワーカー スレッドはプロセス全体を存続させます。