multiprocessing.Pool挂起,如果孩子导致分段错误

时间:2014-06-23 16:34:07

标签: python numpy multiprocessing scikit-learn

我想使用multiprocessing.Pool并行应用函数。 问题是如果一个函数调用触发了分段错误,则Pool会永久挂起。 有没有人知道如何让一个Pool能够检测出这样的事情发生时会引发错误?

以下示例显示了如何重现它(需要scikit-learn> 0.14)

import numpy as np
from sklearn.ensemble import gradient_boosting
import time

from multiprocessing import Pool

class Bad(object):
    tree_ = None


def fit_one(i):
    if i == 3:
        # this will segfault                                                    
        bad = np.array([[Bad()] * 2], dtype=np.object)
        gradient_boosting.predict_stages(bad,
                                         np.random.rand(20, 2).astype(np.float32),
                                         1.0, np.random.rand(20, 2))
    else:
        time.sleep(1)
    return i


pool = Pool(2)
out = pool.imap_unordered(fit_one, range(10))
# we will never see 3
for o in out:
    print o

4 个答案:

答案 0 :(得分:2)

这是known bug, issue #22393, in Python。只要您使用multiprocessing.pool直到修复它,就没有有意义的解决方法。该链接提供了一个补丁,但尚未将其集成到主版本中,因此没有稳定版本的Python可以解决问题。

答案 1 :(得分:1)

您可能希望自己使用Pool().imap()手动创建子流程,而不是使用Process()。我敢打赌,返回的对象可以让你获得任何孩子的活跃状态。你会知道他们是否挂断了。

答案 2 :(得分:1)

如评论中所述,如果您使用concurrent.Futures.ProcessPoolExecutor而不是multiprocessing.Pool,这只适用于Python 3。

如果您遇到Python 2,我发现的最佳选择是在timeoutPool.apply_async返回的结果对象上使用Pool.map_async参数。例如:

pool = Pool(2)
out = pool.map_async(fit_one, range(10))
for o in out:
    print o.get(timeout=1000)  # allow 1000 seconds max

只要你有一个上限来确定子进程完成一项任务应该花多长时间,这就行了。

答案 3 :(得分:0)

我没有运行你的例子,看看它是否可以处理错误,但尝试并发期货。只需用fit_one(i)替换my_function(i)即可。保持__name__=='__main__':结构。并行期货似乎需要这个。下面的代码在我的机器上测试,所以希望能直接在你的机器上进行测试。

import concurrent.futures

def my_function(i):
    print('function running')
    return i

def run():
    number_processes=4
    executor = concurrent.futures.ProcessPoolExecutor(number_processes)
    futures = [executor.submit(my_function,i) for i in range(10)]
    concurrent.futures.wait(futures)

    for f in futures:
        print(f.result())

if __name__ == '__main__':
    run()