Как мне вызвать функцию или как ее обернуть, чтобы, если она занимает больше 5 секунд, скрипт отменяет ее?
Я отправил gist , который решает этот вопрос / проблему с декоратором и
threading.Timer
. Здесь он с разбивкой.Импорт и настройки для совместимости
Он был протестирован с Python 2 и 3. Он также должен работать под Unix / Linux и Windows.
Сначала импорт. Эти попытки сохранить код совместимым независимо от версии Python:
from __future__ import print_function import sys import threading from time import sleep try: import thread except ImportError: import _thread as thread
Использовать независимый от версии код:
try: range, _print = xrange, print def print(*args, **kwargs): flush = kwargs.pop('flush', False) _print(*args, **kwargs) if flush: kwargs.get('file', sys.stdout).flush() except NameError: pass
Теперь мы импортировали наши функции из стандартной библиотеки.
exit_after
decoratorДалее нам нужна функция для завершения
main()
из дочернего потока:def quit_function(fn_name): # print to stderr, unbuffered in Python 2. print('{0} took too long'.format(fn_name), file=sys.stderr) sys.stderr.flush() # Python 3 stderr is likely buffered. thread.interrupt_main() # raises KeyboardInterrupt
И вот сам декоратор :
def exit_after(s): ''' use as decorator to exit process if function takes longer than s seconds ''' def outer(fn): def inner(*args, **kwargs): timer = threading.Timer(s, quit_function, args=[fn.__name__]) timer.start() try: result = fn(*args, **kwargs) finally: timer.cancel() return result return inner return outer
Использование
И вот использование, которое напрямую отвечает на ваш вопрос об окончании через 5 секунд!:
@exit_after(5) def countdown(n): print('countdown started', flush=True) for i in range(n, -1, -1): print(i, end=', ', flush=True) sleep(1) print('countdown finished')
Демонстрация:
>>> countdown(3) countdown started 3, 2, 1, 0, countdown finished >>> countdown(10) countdown started 10, 9, 8, 7, 6, countdown took too long Traceback (most recent call last): File "
", line 1, in File " ", line 11, in inner File " ", line 6, in countdown KeyboardInterrupt Второй вызов функции не будет завершен, вместо этого процесс должен выйти с трассировкой!
KeyboardInterrupt
не всегда останавливает спальный потокОбратите внимание, что спящий режим не всегда прерывается прерыванием клавиатуры на Python 2 в Windows, например:
@exit_after(1) def sleep10(): sleep(10) print('slept 10 seconds') >>> sleep10() sleep10 took too long # Note that it hangs here about 9 more seconds Traceback (most recent call last): File "
", line 1, in File " ", line 11, in inner File " ", line 3, in sleep10 KeyboardInterrupt , и он не может прервать работу кода в расширениях, если он явно не проверяет наличие
PyErr_CheckSignals()
, см. Cython, Python и KeyboardInterrupt игнорируютсяЯ бы избежал спящего потока более секунды, в любом случае - это эон времени процессора.
] Как мне вызвать функцию или как ее обернуть, чтобы, если она занимает больше 5 секунд, скрипт отменяет ее и делает Что-то еще?
Чтобы поймать его и сделать что-то еще, вы можете поймать KeyboardInterrupt.
>>> try: ... countdown(10) ... except KeyboardInterrupt: ... print('do something else') ... countdown started 10, 9, 8, 7, 6, countdown took too long do something else
Удаление D:\home\data\Functions\secrets
решило проблему.
В целом я узнал, что при любом странном поведении, которое вы получаете от Azure Function, Куду всегда является вашим лучшим инструментом для расследования.
В сообщении указывалось, что это связано с ключами (секретами) уровня хоста в вашей функции.
Поэтому, хотя у меня нет чёткого решения этой проблемы (поскольку я никогда не сталкивался с этой проблемой), я бы посоветовал вам проверить папку host.json
в D:\home\data\Functions\secrets
и посмотреть, есть ли там что-нибудь необычное, например, есть более 10 клавиш - как указано в сообщении об ошибке.