简体   繁体   English

如何处理multiprocessing.Pool中的初始化错误?

[英]How to handle initializer error in multiprocessing.Pool?

When initializer throw Error like below, script won't stop. 当初始化器抛出如下错误时,脚本不会停止。
I would like to abort before starting main process(do not run 'do_something'). 我想在开始主进程之前中止操作(不要运行“ do_something”)。

from multiprocessing import Pool
import contextlib

def initializer():
    raise Exception("init failed")

def do_something(args):
    # main process
    pass

pool = Pool(1, initializer=initializer)
with contextlib.closing(pool):
    try:
        pool.map_async(do_something, [1]).get(100)
    except:
        pool.terminate()

The never stopping stacktrace on console is below 控制台上永不停止的stacktrace在下面

...
Exception: init failed
Process ForkPoolWorker-18:
Traceback (most recent call last):
  File "/home/hoge/anaconda3/lib/python3.6/multiprocessing/process.py", line 249, in _bootstrap
    self.run()
  File "/home/hoge/anaconda3/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/home/hoge/anaconda3/lib/python3.6/multiprocessing/pool.py", line 103, in worker
    initializer(*initargs)
  File "hoge.py", line 5, in initializer
    raise Exception("init failed")
Exception: init failed
...

My workaround is suppressing initializer error and return at the beginning of the main process by using global flag like below. 我的解决方法是抑制初始化错误并通过使用如下所示的全局标志在主进程的开始处返回。
But I would like to learn better one. 但我想学得更好。

def initializer():
    try:
        raise Exception("init failed")
    except:
        global failed
        failed = True

def do_something(args):
    global failed
    if failed:
        # skip when initializer failed
        return
    # main process

After navigating through the implementation of multiprocessing using PyCharm, I'm convinced that there is no better solution, because Pool started a thread to _maintain_pool() by _repopulate_pool() if any worker process exists--either accidentally or failed to initialize. 在使用PyCharm实现了多处理的实现之后,我确信没有更好的解决方案,因为如果存在任何辅助进程,则Pool会通过_repopulate_pool()启动到_maintain_pool()的线程-偶然或初始化失败。

Check this out: Lib/multiprocessing/pool.py line 244 检查一下: Lib / multiprocessing / pool.py第244行

I just came across the same woe. 我只是遇到了同样的麻烦。 My first solution was to catch the exception and raise it in the worker function (see below). 我的第一个解决方案是捕获异常并在worker函数中引发它(请参见下文)。 But on second thought it really means that initializer support of multiprocessing.Pool is broken and sould not be used. 但经过深思熟虑,这的确意味着multiprocessing.Pool initializer支持。 multiprocessing.Pool已损坏且无法使用。 So I now prefer to do the initialization stuff directly in the worker. 因此,我现在更喜欢直接在worker中进行初始化工作。

from multiprocessing import Pool
import contextlib, sys

_already_inited = False
def initializer():
    global _already_inited
    if _already_inited:
        return
    _already_inited = True
    raise Exception("init failed")

def do_something(args):
    initializer()
    # main process

pool = Pool(1)
with contextlib.closing(pool):
    pool.map_async(do_something, [1]).get(100)

Both the code and the stacktrace are simpler. 代码和stacktrace都更简单。 Off course all your worker function need to call initializer() . 当然,您的所有辅助函数都需要调用initializer()

My initial solution was to defer the exception to the worker function. 我最初的解决方案是将异常延迟给worker函数。

from multiprocessing import Pool
import contextlib, sys

failed = None
def initializer():
    try:
        raise Exception("init failed")
    except:
        global failed
        failed = sys.exc_info()[1]

def do_something(args):
    global failed
    if failed is not None:
        raise RuntimeError(failed) from failed
    # main process

pool = Pool(1, initializer=initializer)
with contextlib.closing(pool):
    pool.map_async(do_something, [1]).get(100)

That way the caller still gets access to the exception. 这样,调用方仍然可以访问异常。

multiprocessing.pool.RemoteTraceback:  
""" 
Traceback (most recent call last): 
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 119, in worker 
    result = (True, func(*args, **kwds)) 
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 44, in mapstar 
    return list(map(*args)) 
  File "/tmp/try.py", line 15, in do_something 
    raise RuntimeError(failed) 
RuntimeError: init failed 
""" 

The above exception was the direct cause of the following exception: 

Traceback (most recent call last): 
  File "/tmp/try.py", line 20, in <module> 
    pool.map_async(do_something, [1]).get(100) 
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 608, in get 
    raise self._value 
RuntimeError: init failed 
(venv) kmkaplan@dev1:~/src/options$ python3 /tmp/try.py  
multiprocessing.pool.RemoteTraceback:  
""" 
Traceback (most recent call last): 
  File "/tmp/try.py", line 7, in initializer 
    raise Exception("init failed") 
Exception: init failed 

The above exception was the direct cause of the following exception: 

Traceback (most recent call last): 
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 119, in worker 
    result = (True, func(*args, **kwds)) 
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 44, in mapstar 
    return list(map(*args)) 
  File "/tmp/try.py", line 15, in do_something 
    raise RuntimeError(failed) from failed 
RuntimeError: init failed 
""" 

The above exception was the direct cause of the following exception: 

Traceback (most recent call last): 
  File "/tmp/try.py", line 20, in <module> 
    pool.map_async(do_something, [1]).get(100) 
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 608, in get 
    raise self._value 
RuntimeError: init failed 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM