假设您发现自己处于对一个表现不佳的库的依赖的不幸位置。您的代码需要调用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().")
答案 0 :(得分:4)
我不能说Python 2.7,但在Python 3中,正确处理这个问题的方法是使用asyncio
和futures的概念。
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().")