Когда мы запрашиваем стороннюю библиотеку, используя сеть, такую как запросы, мы видим, что у нее есть параметр с именемtimeout
, что означает, что расчет начинается при отправке сетевого запроса.Если время ожидания превышено, а возврат не получен, создается исключение времени ожидания. (Конечно, есть особые случаи, когда время ожидания будет недействительным, см.Timeouts and cancellation for humans*Пример автора в этой статье мы не рассматриваем этот частный случай).
Но задумывались ли вы когда-нибудь, как установить тайм-аут для обычных функций? В частности, при выполнении некоторой обработки данных и кода, связанного с ИИ, функция может выполняться в течение длительного времени.Мы хотим понять, что, когда функция выполняется дольше определенного времени, об ошибке будет сообщено автоматически.
Например, есть такой сценарий, я написал функциюcalc_statistic(datas)
, который вычисляет значение на основе данных, переданных пользователем. Но если данные, переданные пользователем, очень велики, эта функция может работать долгое время. Я хочу, чтобы эта функция работала до 10 секунд. Если запуск не завершен в течение 10 секунд, выдается сообщение об ошибке. Как я должен это делать?
Если на вашем компьютере установлена операционная система Linux или macOS, вы можете использовать сигнал для ее решения.
В статье, опубликованной несколько дней назад на официальном аккаунте, мы представили использование сигнала для приема сигнала прерывания клавиатуры.signal.SIGINT
. Сегодня мы будем использоватьsignal.SIGALRM
.
Во-первых, давайте посмотрим, как используется этот сигнал:
import time
import signal
def handler(signum, _):
print('定时到!')
raise Exception('定时到了!')
def clac_statistic(datas):
time.sleep(100)
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)
clac_statistic('xxx')
Эффект операции показан на следующем рисунке:
связывать первымsignal.SIGALRM
событие дляhandler
функцию, затем используйтеsignal.alarm(10)
Отправить сигнал с 10-секундной задержкой. Через 10 секунд функцияhandler
работает. В функции возникло исключение, что привело к завершению программы.clac_statistic
Функция должна была работать в течение 100 секунд, но остановилась через 10 секунд, тем самым реализуя функцию тайм-аута функции.
Основываясь на вышеизложенных принципах, мы реализуем декоратор, чтобы упростить настройку функции тайм-аута для разных функций:
import time
import signal
class FuncTimeoutException(Exception):
pass
def handler(signum, _):
raise FuncTimeoutException('函数定时到了!')
def func_timeout(times=0):
def decorator(func):
if not times:
return func
def wraps(*args, **kwargs):
signal.alarm(times)
result = func(*args, **kwargs)
signal.alarm(0) # 函数提前运行完成,取消信号
return result
return wraps
return decorator
signal.signal(signal.SIGALRM, handler)
Мы пытаемся протестировать эту функцию декоратора тайм-аута. Первая тестовая функция времени работы меньше таймаута, программа работает без проблем:
Проверим случай, когда время работы функции превышает время ожидания:
нормальный бросокFuncTimeoutException
аномальный.
Тогда в реальном использовании мы можем использоватьtry...except FuncTimeoutException
Перехватите это исключение и реализуйте собственный поток обработки, например:
try:
clac_statistic(100)
except FuncTimeException:
print('该函数运行超时,运行自定义的处理流程')
Конечно, если вы хотите напрямую пропустить это исключение, нет проблем:
import contextlib:
with contextlib.supress(FuncTimeException):
clac_statistic(100)