Завершение программы в python

Привет, я внедрил ограничение по времени в свой код Python, который запускает код fortran с функцией. Однако я понял, что функция, которая накладывает ограничение по времени на другую функцию, не завершает код, а просто оставляет его в фоновом режиме и вместо этого пропускает. Что я хочу сделать, так это завершить код, когда он превысит ограниченное время. Вот код, который я использую для ограничения времени, взятый из здесь.

def timeout(func, args=(), kwargs={}, timeout_duration=15, default=1):
    import signal

    class TimeoutError(Exception):
        pass

    def handler(signum, frame):
        raise TimeoutError()

    # set the timeout handler                                                                                                                                             
    signal.signal(signal.SIGALRM, handler)
    signal.alarm(timeout_duration)
    try:
        result = func(*args, **kwargs)
    except TimeoutError as exc:
        result = default
    finally:
        signal.alarm(0)

    return result

Я искал popen.terminate(), sys.exit() и atexit.register(), но не мог понять, как это будет работать с этим фрагментом кода, который я пытался добавить в части ниже, которую я показал в комментарии.

...
        result = func(*args, **kwargs)
    except TimeoutError as exc:
        result = default
#add the terminator
    finally:
...

ПРИМЕЧАНИЕ. Функция находится внутри цепочки циклов for, поэтому я не хочу убивать весь сеанс python, а просто хочу убить программу, которую запускает эта функция, которая является кодом fortran, и перейти к другому элементу в цепочке цикла for.

Часть ниже добавлена ​​после некоторых комментариев и ответов:

Я попытался добавить SIGTERM с помощью popen.terminate(), однако он завершил весь сеанс python, который я просто хочу завершить текущий запущенный сеанс и перейти к другим элементам в цикле for. я сделал следующее:

...
    signal.signal(signal.SIGTERM, handler) 
    signal.alarm(timeout_duration)
    try:
        result = func(*args, **kwargs)
    except TimeoutError as exc:
        result = default
        popen.terminate()
...

person jackaraz    schedule 31.03.2016    source источник
comment
что вы подразумеваете под программой, которую запускает эта функция? Это внешний процесс, запущенный модулем subprocess? Существуют ли процессы-потомки? Процесс завершается, если вы отправляете сигнал SIGTERM? Какая у вас версия Python? Должно быть достаточно передать параметр timeout в process.wait() и вызвать process.terminate() по TimeoutError, если потомков нет и процесс завершается на SIGTERM.   -  person jfs    schedule 31.03.2016
comment
@ J.F.Sebastian этот код запускает функцию, которая запускает код на фортране, который я хочу ограничить временем выполнения для сохранения из процессора. Все, что делает эта функция, это оставляет код fortran в фоновом режиме и переходит к другому элементу в цикле for, который накапливается в процессоре после 100 циклов, скажем, поэтому я хочу завершить сеанс, прежде чем перейти к другому элементу. Питон версии 2.7.   -  person jackaraz    schedule 01.04.2016
comment
@jackaraz снова, означает ли запуск кода на фортране, что вы запускаете внешний процесс, используя модуль subprocess? (Например, библиотека numpy выполняет большое количество кода на Фортране без запуска нового процесса). Чтобы ограничить количество одновременных процессов, см. этот ответ.   -  person jfs    schedule 01.04.2016
comment
@ J.F.Sebastian да, я использую subprocess.check_output('./../bin/SPhenoUMSSM ../UMSSM/LH_out_'+mod+' > SPheno_log_'+mod, shell=True) в другой функции для запуска кода на фортране   -  person jackaraz    schedule 01.04.2016
comment
@jackaraz : где ты тогда берешь popen?   -  person jfs    schedule 01.04.2016
comment
@ J.F.Sebastian Я никогда не использовал его раньше, просто пробовал предложения, написанные ниже, чтобы посмотреть, работает ли он.   -  person jackaraz    schedule 01.04.2016
comment
Ответ можно найти по этой ссылке.   -  person jackaraz    schedule 30.09.2016


Ответы (1)


Вы не можете ожидать, что обработчик сигнала, вызывающий исключение, будет распространяться через стек вызовов, он вызывается в другом контексте.

popen.terminate() будет генерировать SIGTERM в системах posix, поэтому у вас должен быть обработчик сигнала для SIGTERM, а не SIGALRM.

Вместо того, чтобы вызывать исключение в вашем обработчике сигналов, вы должны установить некоторую переменную, которую вы периодически проверяете, чтобы остановить активность.

В качестве альтернативы, если у вас нет обработчика сигнала для SIGTERM, обработчик по умолчанию, вероятно, сгенерирует исключение KeyboardInterrupt.

person Brian Cain    schedule 31.03.2016
comment
Итак, вы предлагаете использовать popen.terminate() с SIGTERM? потому что альтернатива, которую вы предложили, звучит так: если я правильно понимаю, будет завершен весь сеанс python, который я не хочу делать, потому что этот фрагмент находится в цепочке циклов for, поэтому я просто хочу завершить этот конкретный сеанс и перейти к другим элементам в цикл for. - person jackaraz; 31.03.2016
comment
1-исключения распространяются в основном потоке. Проблема может заключаться в том, что func() может (из-за ошибки) забыть вызвать PyErr_CheckSignal() для EINTR в своем коде C, и поэтому обработчик сигналов Python не вызывается до тех пор, пока func() не вернет управление интерпретатору. 2- Какой смысл отправлять SIGTERM в процесс python. Кажется, OP вместо этого хочет завершить дочерний процесс. Целью SIGALRM является прерывание любого процесса Python, например, process.wait(). 3- если код может периодически проверять переменную, если только код не находится в потоке; проще вызвать исключение - person jfs; 31.03.2016