是否有任何并发​​超时功能有效?

时间:2019-01-02 18:43:10

标签: python multiprocessing timeout concurrent.futures

试图廉价地编写基于进程的超时(同步),如下所示:

from concurrent.futures import ProcessPoolExecutor

def call_with_timeout(func, *args, timeout=3):
    with ProcessPoolExecutor(max_workers=1) as pool:
        future = pool.submit(func, *args)
        result = future.result(timeout=timeout)

但是似乎传递给future.resulttimeout参数实际上并没有像宣传的那样起作用。

>>> t0 = time.time()
... call_with_timeout(time.sleep, 2, timeout=3)
... delta = time.time() - t0
... print('wall time:', delta)
wall time: 2.016767978668213

好。

>>> t0 = time.time()
... call_with_timeout(time.sleep, 5, timeout=3)
... delta = time.time() - t0
... print('wall time:', delta)
# TimeoutError

不正常- 5秒后解锁,而不是3秒。

相关问题显示了如何使用线程池或signal执行此操作。如何在 n 秒后使提交给池的进程超时,而不使用任何_private API的多处理功能?硬杀是可以的,无需请求彻底关闭。

2 个答案:

答案 0 :(得分:2)

超时表现应有的表现。给定超时后future.result(timeout=timeout)停止。 关闭池仍在等待所有未完成的期货执行完毕,这会导致意外的延迟。

您可以通过调用shutdown(wait=False)使关闭在后台发生,但是整个Python程序要等到所有未完成的期货执行完毕才能结束:

def call_with_timeout(func, *args, timeout=3):
    pool = ProcessPoolExecutor(max_workers=1)
    try:
        future = pool.submit(func, *args)
        result = future.result(timeout=timeout)
    finally:
        pool.shutdown(wait=False)

Executor API无法取消已执行的调用。 future.cancel()只能取消尚未开始的呼叫。如果您想要突然中止功能,则可能应该使用concurrent.futures.ProcessPoolExecutor以外的其他方式。

答案 1 :(得分:1)

您可能想看看pebble

它的ProcessPool旨在解决这个确切的问题:无需关闭整个缓冲池即可启用超时并取消正在运行的任务。

当未来超时或被取消时,工作人员实际上被终止,有效地停止了计划功能的执行。

超时:

pool = pebble.ProcessPool(max_workers=1)
future = pool.schedule(func, args=args, timeout=1)
try:
    future.result()
except TimeoutError:
    print("Timeout")

示例:

def call_with_timeout(func, *args, timeout=3):
    pool = pebble.ProcessPool(max_workers=1)
    with pool:
        future = pool.schedule(func, args=args, timeout=timeout)
        return future.result()