1. ホーム
  2. python

[解決済み] マルチプロセッシングで投げられる例外 プールが検出されない

2023-07-24 14:12:43

質問

multiprocessing.Pool プロセスから例外が発生したとき、スタックトレースやその他の失敗したことを示すものがないようです。例を示します。

from multiprocessing import Pool 

def go():
    print(1)
    raise Exception()
    print(2)

p = Pool()
p.apply_async(go)
p.close()
p.join()

は1を表示し、静かに停止します。興味深いことに、代わりにBaseExceptionを発生させると動作します。すべての例外の動作をBaseExceptionと同じにする方法はないのでしょうか?

どのように解決するのですか?

少なくともデバッグの目的では、この問題に対する合理的な解決策があります。私は現在、メイン プロセスに戻って例外を発生させるような解決策を持っていません。最初に考えたのはデコレーターを使用することでしたが、ピックルできるのは 関数はモジュールのトップ レベルで定義された をピクルスすることしかできないので、それは正しい選択ではありません。

代わりに、シンプルなラッピングクラスと、これを利用したPoolのサブクラスで apply_async (そして、それ故に apply ). を残すことにします。 map_async を読者のための練習として残しておきます。

import traceback
from multiprocessing.pool import Pool
import multiprocessing

# Shortcut to multiprocessing's logger
def error(msg, *args):
    return multiprocessing.get_logger().error(msg, *args)

class LogExceptions(object):
    def __init__(self, callable):
        self.__callable = callable

    def __call__(self, *args, **kwargs):
        try:
            result = self.__callable(*args, **kwargs)

        except Exception as e:
            # Here we add some debugging help. If multiprocessing's
            # debugging is on, it will arrange to log the traceback
            error(traceback.format_exc())
            # Re-raise the original exception so the Pool worker can
            # clean up
            raise

        # It was fine, give a normal answer
        return result

class LoggingPool(Pool):
    def apply_async(self, func, args=(), kwds={}, callback=None):
        return Pool.apply_async(self, LogExceptions(func), args, kwds, callback)

def go():
    print(1)
    raise Exception()
    print(2)

multiprocessing.log_to_stderr()
p = LoggingPool(processes=1)

p.apply_async(go)
p.close()
p.join()

これで

1
[ERROR/PoolWorker-1] Traceback (most recent call last):
  File "mpdebug.py", line 24, in __call__
    result = self.__callable(*args, **kwargs)
  File "mpdebug.py", line 44, in go
    raise Exception()
Exception