如何保护自己免受可能无限期挂起的片状图书馆电话的侵扰?

时间:2016-04-28 02:01:12

标签: python

假设您发现自己处于对一个表现不佳的库的依赖的不幸位置。您的代码需要调用FlakyClient.call(),但有时该函数最终会挂起不可接受的时间。

如下所示,解决此问题的一种方法是将呼叫包装在自己的进程中,并使用 join 方法中的timeout参数来定义最大量你愿意在FlakyClient上等待的时间。这提供了一个很好的安全措施,但它也阻止了代码主体对调用FlakyClient.call()的结果作出反应。我知道解决另一个问题(将结果放入代码主体)的唯一方法是使用一些繁琐的IPC技术。

处理这两个问题的干净和pythonic方法是什么?如果库调用挂起,我想保护自己,并且如果调用完成,我可以使用结果。

谢谢!

from multiprocessing import Process
from flaky.library import FlakyClient


TIMEOUT_IN_SECS = 10

def make_flaky_call():
    result = FlakyClient.call()

proc = Process(target=make_flaky_call)
proc.start()
proc.join(TIMEOUT_IN_SECS)
if proc.is_alive():
    proc.terminate()
    raise Exception("Timeout during call to FlakyClient.call().")

2 个答案:

答案 0 :(得分:4)

我不能说Python 2.7,但在Python 3中,正确处理这个问题的方法是使用asynciofutures的概念。

import concurrent

def make_flaky_call():
    return FlakyClient.call()

timeout = 10

with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
    future = executor.submit(make_flaky_call) # get a future object
    try:
        result = await future.result(timeout = timeout)
    except concurrent.futures.TimeOutError:
        # if a timeout occurs on the call, do something
        result = None # default value

这是相当Pythonic。您可以将其与代码的主体集成。它正确使用try-except进行错误处理。它带有内置超时。它仅适用于Python 3.5(感谢await - 但更改为yield from使其与Python 3.4兼容。)

对于Python 2.7,遗憾的是,处理它的正确方法是执行您当前正在执行的操作。

答案 1 :(得分:2)

如果您正在使用Process,我建议您使用Queue来处理结果传输,并间接管理函数超时。

from multiprocessing import Process, Queue
from flaky.library import FlakyClient
import time

TIMEOUT_IN_SECS = 10

def make_flaky_call(queue):
    result = FlakyClient.call()
    queue.put(result)
    queue.put('END')

q = Queue()
proc = Process(target=make_flaky_call, args=(q,))
proc.start()
content = 0
result = None
while content != 'END':
    try:
        content = q.get(timeout=TIMEOUT_IN_SECS)
        if content != 'END':
            result = content
    except Empty:
        proc.terminate()
        raise Exception("Timeout during call to FlakyClient.call().")