[英]How do you create a timeout in a for-loop in Python?
I have a for loop that retrieves data from an API:我有一个从 API 检索数据的 for 循环:
app = WebService()
for i in items:
result = app.request(item)
I want to create a timeout so that, if the app.request
blocking call takes too long, the loop will skip it and go to the next item.我想创建一个超时,这样,如果app.request
阻塞调用花费太长时间,循环将跳过它,go 到下一个项目。
I have read some ways of creating a timer by using a while
loop, but I believe in my case I cannot create a while
loop inside the for
loop with a continue
clause that would apply to the for
loop... So, how can I do this?我已经阅读了一些使用while
循环创建计时器的方法,但我相信在我的情况下,我无法在 for 循环中创建一个while
循环,并使用适用for
for
的continue
子句......那么,我该怎么做做这个?
Unfortunately, the API doesn't provide a way to create a timeout.不幸的是,API 没有提供创建超时的方法。 It is not an HTTP call to a REST API.它不是对 REST API 的 HTTP 调用。
Based on this answer .基于这个答案。
This is a good use-case for a decorator .这是一个很好的装饰器用例。 The decorator pattern is useful when you want to wrap a function or class method with additional functionality.当您想要包装具有附加功能的 function 或 class 方法时,装饰器模式很有用。
This is the equivalent of how to do a Python 3 timeout decorator using the Python's signal
library.这相当于如何使用 Python 的signal
库执行 Python 3 超时装饰器。
Once you have the decorator, wrap your app.request in a decorated
function and handle the exception with a try-except.一旦你有了装饰器,将你的 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()
You can try it fast on this repl.it您可以在此 repl.it上快速尝试
Additionally, if you do not want to "hide" the API call inside the function, you can do dependency inversion.此外,如果您不想在 function 中“隐藏” API 调用,则可以进行依赖倒置。 That is, your decorated function does not depend on any request
function implementation in particular.也就是说,您装饰的 function 不依赖于任何request
function 实现。 To do this, you receive the function itself as an argument.为此,您收到 function 本身作为参数。 See below:见下文:
# 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.