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

Python multiprocessing.Queue が join で停止?feeder と drain の順序を可視化する

process、feeder thread、unfinished task の三つの待機を区別し、silent data loss を避けて終了順序を直します。

Python multiprocessing Queue の join 待機関係図
オリジナルイラスト:join と feeder、pipe、reader の待機関係を先に特定します。 Watch at Ease

子 process が target function を終えても、Queue feeder が誰も読まない pipe へ buffer を flush していれば終了できません。見えている join は待機鎖の末端です。

どの join かを特定し、writer、feeder、pipe、reader の所有関係を描いてから drain と close の順序を修正します。

1. 停止している join を正確に特定する

何かを terminate する前に thread/process stack を保存します。Process.join は child exit、Queue.join_thread は close 後の feeder exit、JoinableQueue.join は全 task_done を待ちます。

start method、Python version、OS、queue type、creator、producer、consumer、最後の put/get/task_done を記録し、qsize を証拠にしません。

2. writer–feeder–pipe–reader の待機図を作る

Queue.put 後、background feeder が object を serialize して pipe へ送ります。reader が止まり pipe が満杯になると feeder の write が停止し、producer の終了も flush 待ちになります。

全 read/write end、close owner、sentinel sender、待機中も読む actor を列挙します。pipe capacity は有限で正しさの前提にはできません。

3. 所有契約に沿って順序を修正する

result queue は worker が生きている間に drain し、全 producer を先に join しません。新規 work を止め、必要数の sentinel、必要 result の drain、writer close、feeder/process join の順を待機図で決めます。

JoinableQueue は成功した get ごとに例外時も一度だけ task_done を呼び、unfinished count を減らす consumer を join で塞ぎません。

4. cancel_join_thread と terminate を損失判断として扱う

cancel_join_thread は feeder flush を待たずに exit できるため buffer data を失う可能性があります。明示的な loss policy と test がある場合だけ使います。

terminate/kill も queue state や in-flight bytes を壊し得るため、replay、deduplicate、abandon の境界を先に定義します。

5. 正常終了と完全配送を同時に証明する

通常の pipe capacity を超える payload で produced/consumed ID を照合し、deployment と同じ start method で繰り返します。exit だけでなく全 record、feeder 消滅、exit code、破損なしを確認します。

reader を停止する negative test では bounded backpressure または controlled timeout を観測し、silent drop を許しません。

Queue の drain 順序と受入条件
オリジナルイラスト:所有関係と順序を直し、終了と完全配送を確認します。 Watch at Ease