Я вызываю функцию в Python, которая, я знаю, может остановить и заставить меня перезапустить скрипт.
Как мне вызвать функцию или как ее обернуть, чтобы, если это заняло более 5 секунд, скрипт отменил ее и сделал что-то еще?
Я вызываю функцию в Python, которая, я знаю, может остановить и заставить меня перезапустить скрипт.
Как мне вызвать функцию или как ее обернуть, чтобы, если это заняло более 5 секунд, скрипт отменил ее и сделал что-то еще?
Вы можете использовать пакет сигналов , если вы работаете в UNIX:
In [1]: import signal
# Register an handler for the timeout
In [2]: def handler(signum, frame):
...: print("Forever is over!")
...: raise Exception("end of time")
...:
# This function *may* run for an indetermined time...
In [3]: def loop_forever():
...: import time
...: while 1:
...: print("sec")
...: time.sleep(1)
...:
...:
# Register the signal function handler
In [4]: signal.signal(signal.SIGALRM, handler)
Out[4]: 0
# Define a timeout for your function
In [5]: signal.alarm(10)
Out[5]: 0
In [6]: try:
...: loop_forever()
...: except Exception, exc:
...: print(exc)
....:
sec
sec
sec
sec
sec
sec
sec
sec
Forever is over!
end of time
# Cancel the timer if the function returned before timeout
# (ok, mine won't but yours maybe will :)
In [7]: signal.alarm(0)
Out[7]: 0
Через 10 секунд после вызова вызывается alarm.alarm(10)
обработчик. Это вызывает исключение, которое вы можете перехватить из обычного кода Python.
Этот модуль плохо работает с потоками (но тогда, кто делает?)
Обратите внимание, что, поскольку мы генерируем исключение, когда происходит тайм-аут, оно может в конечном итоге быть пойманным и проигнорировано внутри функции, например, одной такой функции:
def loop_forever():
while 1:
print('sec')
try:
time.sleep(10)
except:
continue
signal.alarm
и связанные с нимиSIGALRM
недоступны на платформах Windows.signal.signal
--- все ли они будут работать правильно? Разве каждыйsignal.signal
звонок не отменяет «одновременный»?Вы можете использовать,
multiprocessing.Process
чтобы сделать именно это.Код
источник
join()
. это заставляет ваше число одновременных подпроцессов работать до тех пор, пока они не завершат свою работу, или количество, указанное вjoin(10)
. В случае, если у вас есть блокирующий ввод / вывод для 10 процессов, используя join (10), вы установили их так, чтобы они ждали каждого из них максимум 10, пока КАЖДЫЙ процесс не запустился. Используйте флаг демона, как в этом примере stackoverflow.com/a/27420072/2480481 . Конечно, вы можете передать флагdaemon=True
непосредственно вmultiprocessing.Process()
функцию.terminate() ... Note that exit handlers and finally clauses, etc., will not be executed. Note that descendant processes of the process will not be terminated – they will simply become orphaned.
Я опубликовал суть, которая решает этот вопрос / проблему с декоратором и
threading.Timer
. Вот это с разбивкой.Импорт и настройки для совместимости
Он был протестирован с Python 2 и 3. Он также должен работать под Unix / Linux и Windows.
Сначала импорт. Эти попытки сохранить код непротиворечивым независимо от версии Python:
Используйте независимый от версии код:
Теперь мы импортировали нашу функциональность из стандартной библиотеки.
exit_after
декораторДалее нам нужна функция для завершения
main()
дочернего потока:А вот и сам декоратор:
использование
И вот использование, которое прямо отвечает на ваш вопрос о выходе через 5 секунд !:
Демо-версия:
Второй вызов функции не завершится, вместо этого процесс должен завершиться с отслеживанием!
KeyboardInterrupt
не всегда останавливает спящую нитьОбратите внимание, что сон не всегда прерывается прерыванием клавиатуры, на Python 2 в Windows, например:
и при этом он не может прерывать код, выполняемый в расширениях, если он явно не проверяется
PyErr_CheckSignals()
, см. Cython, Python и KeyboardInterrupt игнорируютсяВ любом случае, я бы не спал нить больше секунды - это время процессора.
Чтобы поймать это и сделать что-то еще, вы можете поймать KeyboardInterrupt.
источник
thread.interrupt_main()
, почему я не могу напрямую вызвать исключение?multiprocessing.connection.Client
с этим? - Пытаюсь решить: stackoverflow.com/questions/57817955/…У меня есть другое предложение, которое является чистой функцией (с тем же API, что и предложение по созданию потоков) и, кажется, работает нормально (основываясь на предложениях в этой теме)
источник
timeout
. Гораздо лучше установить значение по умолчаниюNone
и в первой строке функции добавитьkwargs = kwargs or {}
. С Args все в порядке, потому что кортежи не изменяемы.Я наткнулся на эту ветку при поиске таймаута в модульных тестах. Я не нашел ничего простого в ответах или сторонних пакетах, поэтому я написал декоратор ниже, вы можете перейти прямо в код:
Тогда это так же просто, как время ожидания теста или любой функции, которая вам нравится:
источник
Exception
внутри func_wrapper и сделатьpool.close()
после перехвата, чтобы убедиться, что поток всегда умирает, несмотря ни на что. Затем вы можете броситьTimeoutError
или все, что вы хотите после. Кажется, работает на меня.RuntimeError: can't start new thread
. Будет ли это работать, если я проигнорирую это или есть что-то еще, что я могу сделать, чтобы обойти это? Заранее спасибо!stopit
Пакет, найденный на PyPI, кажется обрабатывать таймаут хорошо.Мне нравится
@stopit.threading_timeoutable
декоратор, который добавляетtimeout
параметр к оформленной функции, которая делает то, что вы ожидаете, она останавливает функцию.Проверьте это на pypi: https://pypi.python.org/pypi/stopit
источник
Есть много предложений, но ни одно из них не использует concurrent.futures, что, я думаю, является наиболее разборчивым способом справиться с этим.
Супер просто читать и поддерживать.
Мы создаем пул, отправляем один процесс и затем ждем до 5 секунд, прежде чем вызвать TimeoutError, которую вы можете перехватить и обработать так, как вам нужно.
Родной для python 3.2+ и перенесенной в 2.7 (pip install futures).
Переключение между потоками и процессами так же просто, как замена
ProcessPoolExecutor
наThreadPoolExecutor
.Если вы хотите прекратить процесс по тайм-ауту, я бы посоветовал заглянуть в Pebble .
источник
Отличный, простой в использовании и надежный тайм-декоратор проекта PyPi ( https://pypi.org/project/timeout-decorator/ )
установка :
Использование :
источник
Я являюсь автором wrapt_timeout_decorator
На первый взгляд, большинство решений, представленных здесь, прекрасно работают под Linux - потому что у нас есть fork () и signal (), но в Windows все выглядит немного иначе. А когда речь идет о подпотоках в Linux, вы больше не можете использовать сигналы.
Чтобы порождать процесс под Windows, он должен быть выбираемым - а многие декорированные функции или методы класса - нет.
Таким образом, вам нужно использовать лучший инструмент для выбора, такой как укроп и многопроцессный режим (а не процесс рассола и многопроцессорный режим) - вот почему вы не можете использовать ProcessPoolExecutor (или только с ограниченной функциональностью).
Для самого тайм-аута - вам нужно определить, что означает тайм-аут - потому что в Windows потребуется значительное (и не определяемое) время, чтобы запустить процесс. Это может быть сложно на коротких таймаутах. Предположим, порождение процесса занимает около 0,5 секунды (легко !!!). Если вы даете тайм-аут 0,2 секунды, что должно произойти? Должна ли функция отключаться через 0,5 + 0,2 секунды (так что метод должен работать в течение 0,2 секунды)? Или время вызова вызываемого процесса истечет через 0,2 секунды (в этом случае декорированная функция ВСЕГДА будет иметь тайм-аут, потому что в это время она даже не порождается)?
Также вложенные декораторы могут быть неприятными, и вы не можете использовать сигналы в подпотоке. Если вы хотите создать действительно универсальный, кроссплатформенный декоратор, все это необходимо принять во внимание (и протестировать).
Другие проблемы - передача исключений обратно вызывающей стороне, а также проблемы с ведением журнала (если используется в оформленной функции - запись в файлы в другом процессе НЕ поддерживается)
Я попытался охватить все крайние случаи. Вы можете заглянуть в пакет wrapt_timeout_decorator или, по крайней мере, протестировать свои собственные решения, вдохновленные используемыми там тестами юнитов.
@Alexis Eggermont - к сожалению, у меня нет достаточно комментариев, чтобы прокомментировать - может быть, кто-то еще может уведомить вас - я думаю, что я решил вашу проблему с импортом.
источник
timeout-decorator
не работает в системе Windows, так как Windows не поддерживаетsignal
хорошо.Если вы используете timeout-decorator в системе Windows, вы получите следующее
Некоторые предложили использовать
use_signals=False
но у меня не получалось.Автор @bitranox создал следующий пакет:
Пример кода:
Дает следующее исключение:
источник
from wrapt_timeout_decorator import *
кажется, убивает некоторые из моих других импортов. Например, я получаюModuleNotFoundError: No module named 'google.appengine'
, но не получаю эту ошибку, если не импортирую wrapt_timeout_decoratorМы можем использовать сигналы для того же. Я думаю, что приведенный ниже пример будет полезен для вас. Это очень просто по сравнению с потоками.
источник
try: ... except: ...
всегда плохая идея.источник
У меня была потребность в нестабильных прерываниях по времени (что SIGALARM не может сделать), которые не будут блокироваться time.sleep (что не может сделать подход, основанный на потоках). В итоге я скопировал и слегка изменил код здесь: http://code.activestate.com/recipes/577600-queue-for-managing-multiple-sigalrm-alarms-concurr/
Сам код:
и пример использования:
источник
Вот небольшое улучшение данного решения на основе потоков.
Код ниже поддерживает исключения :
Вызов с 5-секундным таймаутом:
источник
runFunctionCatchExceptions()
определенных функций Python вызывался GIL. Например , следующее никогда, или очень долго, если возвращение вызывается в функции:eval(2**9999999999**9999999999)
. См. Stackoverflow.com/questions/22138190/…