【问题标题】:python process pool with timeout on each process not all of the poolpython 进程池,每个进程都超时,而不是所有池
【发布时间】:2015-07-06 20:35:16
【问题描述】:

我需要运行多个进程,但不是一起运行,例如同时运行 4 个进程。 multiprocessing.Pool 正是我所需要的。但问题是,如果进程持续时间超过超时(例如 3 秒),我需要终止进程。 Pool 只支持等待所有进程的超时,而不是每个进程。这就是我需要的:

def f():
    process_but_kill_if_it_takes_more_than_3_sec()
pool.map(f, inputs)

我找不到一个简单的方法来使用 Pool 超时。有来自 Eli Bendersky 的a solution。这是一个通过Thread.join(timeout) 限制任意函数执行时间的函数。它有效,(尽管它的停止方法效果不佳)。但是这个方法在进程的主线程等待时运行了一个新的不必要的线程,因为我们需要一个超时控制器。应该可以从一个点控制所有超时,如下所示:

import time
from multiprocessing import Process


def f(n):
    time.sleep(n)

timeout = 3
tasks = [1, 2, 4, 1, 8, 2]

procs = []
pool_len = 4
while len(tasks) > 0 or len(procs) > 0:
    if len(tasks) > 0 and len(procs) < pool_len:
        n = tasks.pop(0)
        p = Process(target=f, args=(n,))
        p.start()
        procs.append({'n': n, 'p': p, 't': time.time() + timeout})
    for d in procs:
        if not d['p'].is_alive():
            procs.remove(d)
            print '%s finished' % d['n']
        elif d['t'] < time.time():
            d['p'].terminate()
            procs.remove(d)
            print '%s killed' % d['n']
    time.sleep(0.05)

输出应该是:

1 finished
1 finished
2 finished
4 killed
2 finished
8 killed

问题:有没有办法使用 Pool 来解决这个问题?

【问题讨论】:

    标签: python timeout multiprocessing pool


    【解决方案1】:

    您可以使 f(n) 合作,以便它始终在超时内完成(如在 GUI/网络事件处理程序中)。

    如果你不能让它合作,那么唯一可靠的选择是杀死正在运行该函数的进程

    import multiprocessing as mp
    
    def run_with_timeout(timeout, func, *args):
        receive_end, send_end = mp.Pipe(duplex=False)
        p = mp.Process(target=func, args=args, kwargs=dict(send_end=send_end))
        p.daemon = True
        p.start()
        send_end.close() # child must be the only one with it opened
        p.join(timeout)
        if p.is_alive():
            ####debug('%s timeout', args)
            p.terminate()
        else:
            return receive_end.recv()  # get value from the child
    

    缺点是每次函数调用都需要一个新进程(maxtasksperchild=1Pool 的类比)。

    使用线程池很容易同时运行4个进程:

    #!/usr/bin/env python
    import logging
    import time
    from functools import partial
    from multiprocessing.pool import ThreadPool
    
    debug = logging.getLogger(__name__).debug
    
    def run_mp(n, send_end):
        start = time.time()
        debug('%d starting', n)
        try:
            time.sleep(n)
        except Exception as e:
            debug('%d error %s', n, e)
        finally:
            debug('%d done, elapsed: %.3f', n, time.time() - start)
        send_end.send({n: n*n})
    
    if __name__=="__main__":
        tasks = [1, 2, 4, 1, 8, 2]
    
        logging.basicConfig(format="%(relativeCreated)04d %(message)s", level=logging.DEBUG)
        print(ThreadPool(processes=4).map(partial(run_with_timeout, 3, run_mp), tasks))
    

    输出

    0027 1 starting
    0028 2 starting
    0030 4 starting
    0031 1 starting
    1029 1 done, elapsed: 1.002
    1032 1 done, elapsed: 1.002
    1033 8 starting
    1036 2 starting
    2031 2 done, elapsed: 2.003
    3029 (4,) timeout
    3038 2 done, elapsed: 2.003
    4035 (8,) timeout
    [{1: 1}, {2: 4}, None, {1: 1}, None, {2: 4}]
    

    注意:可能有forking + threading issues;您可以使用 fork-server 进程来解决它们。

    【讨论】:

      猜你喜欢
      • 2016-11-02
      • 1970-01-01
      • 2017-07-03
      • 2011-10-21
      • 1970-01-01
      • 2018-05-14
      • 2018-10-11
      • 2023-01-30
      • 1970-01-01
      相关资源
      最近更新 更多