我有一個shell腳本,通過包含URL的文本文件進行循環,該文件包含我想要訪問並截取的URL。超時功能,如果它需要太長時間才能完成
所有這一切都很簡單。該腳本初始化一個類,該類在運行時創建列表中每個站點的屏幕截圖。有些網站需要很長時間才能加載,有些網站可能根本無法加載。所以我想在一個超時腳本中包裝screengrabber函數,如果函數在10秒內無法完成,則返回False
。
我滿足於最簡單的解決方案,也許設置一個異步計時器,在10秒後返回False,而不管函數內部發生了什麼?
我有一個shell腳本,通過包含URL的文本文件進行循環,該文件包含我想要訪問並截取的URL。超時功能,如果它需要太長時間才能完成
所有這一切都很簡單。該腳本初始化一個類,該類在運行時創建列表中每個站點的屏幕截圖。有些網站需要很長時間才能加載,有些網站可能根本無法加載。所以我想在一個超時腳本中包裝screengrabber函數,如果函數在10秒內無法完成,則返回False
。
我滿足於最簡單的解決方案,也許設置一個異步計時器,在10秒後返回False,而不管函數內部發生了什麼?
在signal的文檔中描述了超時操作的過程。
其基本思想是使用信號處理程序在某個時間間隔內設置警報,並在該定時器到期後引發異常。
請注意,這隻適用於UNIX。
以下是創建裝飾器的實現(將以下代碼保存爲timeout.py
)。
from functools import wraps
import errno
import os
import signal
class TimeoutError(Exception):
pass
def timeout(seconds=10, error_message=os.strerror(errno.ETIME)):
def decorator(func):
def _handle_timeout(signum, frame):
raise TimeoutError(error_message)
def wrapper(*args, **kwargs):
signal.signal(signal.SIGALRM, _handle_timeout)
signal.alarm(seconds)
try:
result = func(*args, **kwargs)
finally:
signal.alarm(0)
return result
return wraps(func)(wrapper)
return decorator
這創建了一個名爲@timeout
的裝飾器,可以應用於任何長時間運行的函數。
因此,在應用程序代碼,您可以使用像這樣的裝飾:
from timeout import timeout
# Timeout a long running function with the default expiry of 10 seconds.
@timeout
def long_running_function1():
...
# Timeout after 5 seconds
@timeout(5)
def long_running_function2():
...
# Timeout after 30 seconds, with the error "Connection timed out"
@timeout(30, os.strerror(errno.ETIMEDOUT))
def long_running_function3():
...
我重寫使用with
聲明大衛的回答,它可以讓你做這樣做:
with timeout(seconds=3):
time.sleep(4)
哪會引發TimeoutError。
的代碼仍然使用signal
,因此僅適用於UNIX:
import signal
class timeout:
def __init__(self, seconds=1, error_message='Timeout'):
self.seconds = seconds
self.error_message = error_message
def handle_timeout(self, signum, frame):
raise TimeoutError(self.error_message)
def __enter__(self):
signal.signal(signal.SIGALRM, self.handle_timeout)
signal.alarm(self.seconds)
def __exit__(self, type, value, traceback):
signal.alarm(0)
Python
你可以很容易地添加一個裝飾器'@ timeout.timeout'作爲靜態方法。然後,您可以輕鬆地在裝飾器或「with」語句之間進行選擇。 – Kevin 2015-10-15 18:09:58
有趣的是,如果在'Timeout(t)'上下文中引發任何錯誤,'__exit__'仍然會被調用,從而避免由引發'TimeOutError'而不是真正的錯誤引起的任何複雜性。這是一個非常可愛的解決方案。 – lucastamoios 2016-10-30 13:38:03
對於所有懶惰的人,誰愛用的庫而不是複製粘貼+代碼片段來自StackOverflow的:https://pypi.python.org/pypi/timeout-decorator – guettli 2017-05-02 12:42:41