テクノロジー · 実用ガイド

Python の queue.join() が止まる理由:未完了台帳とワーカー生存を監査

空のキューと未完了タスク台帳を分け、停止したコンシューマー、番兵、Python 3.13+ の終了方式を証拠で判定します。

Python キューの未完了タスク台帳図
イラスト:空のキューと完了は別の状態です。 Watch at Ease

queue.join() はコンテナが空になることではなく、未完了タスク数がゼロになることを待ちます。put で増え、task_done で減ります。最後の項目を取得したワーカーが例外やキャンセルで終了すれば、empty() が真でも待機は続きます。

成功した get ごとに finally で task_done を一度だけ呼び、join とワーカー終了を同時に監視します。番兵も数えます。即時 shutdown は未処理のまま join を解除し得るため、完了とは扱えません。

1. 停止したカウンターを特定

put、get、task_done ごとにジョブ ID、ワーカー、単調時刻を記録して照合します。empty はコンテナしか示しません。

内部リストや unfinished_tasks を直接変更しないでください。偽の完了や負の値を招きます。

2. 例外時も一度だけ確認

get 成功後の処理を try/finally に入れ、finally で task_done を呼びます。項目を得る前なら呼びません。

業務成否とキュー確認を別に記録し、二重確認を防ぎます。

3. join とワーカーを監視

asyncio では join とワーカーを同時に待ち、ワーカーが先に終われば例外を伝播します。

スレッドでも参照と停止信号を保持し、全消費者停止を検出します。タイムアウトは診断です。

4. 番兵と shutdown を区別

番兵も投入項目なので退出前に task_done が必要です。

shutdown(False) は通常の意味を保ち、shutdown(True) は作業放棄を明示する場合だけ使います。

5. 故障時系列で検証

正常、例外、キャンセル、番兵漏れ、早期終了、二つの shutdown を試験します。

全ジョブの終端状態、終了後の投入禁止、ワーカー停止、放棄表示を確認します。

queue.join 回復判断マトリクス
イラスト:証拠に基づき修復を選びます。 Watch at Ease