[英]How do you create a timeout in a for-loop in Python?
我有一個從 API 檢索數據的 for 循環:
app = WebService()
for i in items:
result = app.request(item)
我想創建一個超時,這樣,如果app.request
阻塞調用花費太長時間,循環將跳過它,go 到下一個項目。
我已經閱讀了一些使用while
循環創建計時器的方法,但我相信在我的情況下,我無法在 for 循環中創建一個while
循環,並使用適用for
for
的continue
子句......那么,我該怎么做做這個?
不幸的是,API 沒有提供創建超時的方法。 它不是對 REST API 的 HTTP 調用。
基於這個答案。
這是一個很好的裝飾器用例。 當您想要包裝具有附加功能的 function 或 class 方法時,裝飾器模式很有用。
這相當於如何使用 Python 的signal
庫執行 Python 3 超時裝飾器。
一旦你有了裝飾器,將你的 app.request 包裝在一個decorated
過的 function 中,並使用 try-except 處理異常。
# main.py
import signal
DEBUG = True
# Custom exception. In general, it's a good practice.
class TimeoutError(Exception):
def __init__(self, value = "Timed Out"):
self.value = value
def __str__(self):
return repr(self.value)
# This is the decorator itself.
# Read about it here: https://pythonbasics.org/decorators/
# Basically, it's a function that receives another function and a time parameter, i.e. the number of seconds.
# Then, it wraps it so that it raises an error if the function does not
# return a result before `seconds_before_timeout` seconds
def timeout(seconds_before_timeout):
def decorate(f):
if DEBUG: print("[DEBUG]: Defining decorator handler and the new function")
if DEBUG: print(f"[DEBUG]: Received the following function >> `{f.__name__}`")
def handler(signum, frame):
raise TimeoutError()
def new_f(*args, **kwargs):
# Verbatim from Python Docs
# > The signal.signal() function allows defining custom handlers to be executed
# when a signal is received.
if DEBUG: print(f"[DEBUG]: in case of ALARM for function `{f.__name__}`, I'll handle it with the... `handler`")
old = signal.signal(signal.SIGALRM, handler)
# See https://docs.python.org/3/library/signal.html#signal.alarm
if DEBUG: print(f"[DEBUG]: setting an alarm for {seconds_before_timeout} seconds.")
signal.alarm(seconds_before_timeout)
try:
if DEBUG: print(f"[DEBUG]: executing `{f.__name__}`...")
result = f(*args, **kwargs)
finally:
# reinstall the old signal handler
signal.signal(signal.SIGALRM, old)
# Cancel alarm.
# See: https://docs.python.org/3/library/signal.html#signal.alarm
signal.alarm(0)
return result
new_f.__name__ = f.__name__
return new_f
return decorate
import time
@timeout(5)
def mytest():
for i in range(1,10):
interval = 2
if DEBUG: print("[DEBUG]: waiting 2 seconds... on purpose")
time.sleep(interval)
print("%d seconds have passed" % (interval * i))
if __name__ == '__main__':
if DEBUG: print("[DEBUG]: Starting program")
mytest()
您可以在此 repl.it上快速嘗試
此外,如果您不想在 function 中“隱藏” API 調用,則可以進行依賴倒置。 也就是說,您裝飾的 function 不依賴於任何request
function 實現。 為此,您收到 function 本身作為參數。 見下文:
# simple decoration
@timeout(5)
def make_request(item):
# assuming `app` is defined
return app.request(item)
# dependency inversion
@timeout(5)
def make_request(request_handler, item):
return request_handler(item)
# and then in your loop...
for i in items:
make_request(app.request, item)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.