私はPythonのマルチプロセッシングモジュールを使用して、科学的な並列処理を行っています。私のコードでは、手間のかかる作業を行ういくつかの作業プロセスと、結果をディスクに保持するライタープロセスを使用しています。書き込まれるデータは、キューを介してワーカープロセスからライタープロセスに送信されます。データ自体はかなり単純で、ファイル名を保持するタプルと2つの浮動小数点数を持つリストのみで構成されています。数時間の処理の後、ライタープロセスはしばしば行き詰まります。より正確には、次のコードブロック
while (True):
try:
item = queue.get(timeout=60)
break
except Exception as error:
logging.info("Writer: Timeout occurred {}".format(str(error)))
ループを終了することはなく、継続的な「タイムアウト」メッセージが表示されます。
また、キューのステータスなどを出力するロギングプロセスも実装しました。上記のタイムアウトエラーメッセージが表示されても、qsize()を呼び出すと常にキューがいっぱいになります(私の場合はsize = 48)。
キューオブジェクトのドキュメントを徹底的に確認しましたが、キューが同時にいっぱいになっているときにget()がタイムアウトを返す理由について考えられる説明が見つかりません。
何か案は?
編集:
空のキュー例外を確実にキャッチするようにコードを変更しました。
while (True):
try:
item = queue.get(timeout=60)
break
except Empty as error:
logging.info("Writer: Timeout occurred {}".format(str(error)))
マルチプロセッシングでは、キューは同期メッセージキューとして使用されます。これはあなたの問題にも当てはまるようです。ただし、これにはget()
メソッドの呼び出し以上のものが必要です。すべてのタスクが処理された後、要素がキューから削除されるようにtask_done()
を呼び出す必要があります。
ドキュメントから:
Queue.task_done()
以前にキューに入れられたタスクが完了したことを示します。キューコンシューマスレッドによって使用されます。 タスクのフェッチに使用されるget()ごとに、後続のtask_done()の呼び出しにより、タスクの処理が完了したことがキューに通知されます。
Join()が現在ブロックしている場合、すべてのアイテムが処理されると再開されます(つまり、キューに入れられたすべてのアイテムに対してtask_done()呼び出しが受信されました)。
ドキュメントには、適切なスレッドキューの使用法のコード例もあります。
コードの場合は次のようになります
while (True):
try:
item = queue.get(timeout=60)
if item is None:
break
# call working fuction here
queue.task_done()
except Exception as error:
logging.info("Writer: Timeout occurred {}".format(str(error)))
マネージャーベースのキューに切り替えると、この問題の解決に役立つはずです。
manager = Manager()
queue = manager.Queue()
詳細については、マルチプロセッシングのドキュメントをここで確認できます: https://docs.python.org/2/library/multiprocessing.html
あまりにも一般的なException
をキャッチし、それがタイムアウトエラーであると想定しています。
次のようにロジックを変更してみてください。
from Queue import Empty
while (True):
try:
item = queue.get(timeout=60)
break
except Empty as error:
logging.info("Writer: Timeout occurred {}".format(str(error)))
print(queue.qsize())
ログラインがまだ印刷されているかどうかを確認します。