【问题标题】:Hard-kill hanging sub-processes in Python's multiprocessing在 Python 的多处理中硬杀挂起子进程
【发布时间】:2016-06-10 16:47:21
【问题描述】:

我有一个 Python 函数,它调用一个 C 函数的包装器(我无法更改)。大多数时候,C 函数非常快,但是当它失败时,调用就会永远挂起。为了缓解这种情况,我使用multiprocessing 暂停通话:

pool = multiprocessing.Pool(processes=4)
try:
    res = pool.apply_async(my_dangerous_cpp_function, args=(bunch, of, vars))
    return res.get(timeout=1.)
except multiprocessing.TimeoutError:
    terminate_pool(pool)
    pool = multiprocessing.Pool(processes=4)

当被调用的函数没有响应任何信号时,如何终止池?

如果我用pool.terminate() 替换terminate_pool(pool),那么对pool.terminate() 的调用也会挂起。相反,我目前正在向所有子进程发送 SIGKILL:

def terminate_pool(pool):
    for p in pool._pool:
        os.kill(p.pid, 9)
    pool.close()  # ok, doesn't hang
    #pool.join()  # not ok, hangs forever

这样,挂起的子进程停止占用 100% 的 CPU,但是我不能调用 pool.terminate() 或 pool.join()(它们挂起),所以我只是将池对象留在后面并创建一个新的。即使他们收到了 SIGKILL,子进程仍然是打开的,所以我的 Python 进程的数量永远不会停止增加......

有没有办法一劳永逸地消灭池及其所有子进程?

【问题讨论】:

    标签: python timeout multiprocessing kill pool


    【解决方案1】:

    标准multiprocessing.Pool 不是为处理工作人员超时而设计的。

    Pebble processing Pool 确实支持超时任务。

    from pebble import process, TimeoutError
    
    with process.Pool() as pool:
        task = pool.schedule(function, args=[1,2], timeout=5)
    
        try:
            result = task.get()
        except TimeoutError:
            print "Task: %s took more than 5 seconds to complete" % task
    

    【讨论】:

    • 谢谢!我试过了,当没有超时发生时它的工作速度更快,但 Pebble 在我的情况下有一个主要问题:我的函数调用是在来自 rospy 的线程中完成的,但是当发生超时时,Pebble 会杀死这些线程。当我使用pebble.process.concurrent 时也会发生同样的情况:在一次调用之后,调用它的 rospy 线程被终止,因此停止做它应该做的其他有用的事情......有没有办法让这些线程保持活力?跨度>
    • 我不知道 rospy 线程内部结构。假设它使用常规线程,那么这是预期的行为。您可以将进程视为一种“线程容器”。如果您终止一个进程(在您的示例中,由于线程挂起),整个容器及其线程将被销毁。这是一个非常强大的设计,因为它允许您将服务与不稳定的代码隔离(并允许您在多个 CPU 上进行扩展)。
    • 在这种情况下,您需要在销毁后重新初始化您的工人。 DB 连接、套接字等就是这种情况。您可以使用initializer 参数来执行此操作。
    • 非常感谢您的 cmets :) 很抱歉我的描述不够精确,但这就是我的布局,以及为什么 Pebble 杀死线程是有问题的。主进程旋转 ROS 线程并创建一个全局 pool = process.Pool() 对象。然后,一个 ROS 线程调用task = pool.schedule(function) 和task.get()。如果对function 的调用挂起,调用task.get() 的ROS 线程(不是执行它的单独进程中的线程)将被杀死。
    • Pebble 只杀死生成的进程(及其所有线程)。不是被调用者。因此,您的代码中存在一些问题。您是否像示例中那样捕获 TimeoutError 异常?尝试将线程逻辑包装在 try: except: 中,看看是哪个异常停止了您的线程。
    猜你喜欢
    • 1970-01-01
    • 2020-08-12
    • 1970-01-01
    • 2014-05-18
    • 2012-03-12
    • 1970-01-01
    • 1970-01-01
    • 2017-11-30
    • 2012-04-03
    相关资源
    最近更新 更多