Ограничение времени выполнения встроенного Python
Если я вставляю интерпретатор Python в программу на C или С++, как в в этом примере, есть ли способ ограничить, как долго интерпретатор работает? Есть ли что-нибудь, чтобы остановить код Python от входа в бесконечный цикл и тем самым предотвратить PyObject_CallObject
(или эквивалент) от когда-либо возвращаемого?
Аналогично, если код Python создает новый поток, есть ли что-нибудь, чтобы остановить этот поток от входа в бесконечный цикл и работать навсегда?
Ответы
Ответ 1
Как вы можете видеть в docs, PyObject_CallObject
не имеет механизма ограничения времени выполнения функции. Также не существует функции API Python C, о которой я знаю, что позволяет приостановить или убить поток, используемый интерпретатором.
Поэтому мы должны быть немного более креативными в том, как остановить поток. Я могу думать о 3 способах, которыми вы могли бы это сделать (от самого безопасного/чистого до самого опасного...
Опросите ваше основное приложение
Идея здесь в том, что ваша функция Python, которая может работать в течение длительного времени, просто вызывает другую функцию внутри вашего основного приложения, используя API C, чтобы проверить, не следует ли ее отключать. Простой результат True/False позволит вам прекратить изящество.
Это безопасное решение, но требует, чтобы вы изменили свой код на Python.
Использовать исключения
Поскольку вы внедряете Interpreter, вы уже используете API-интерфейс C и поэтому можете использовать PyThreadState_SetAsyncExc, чтобы заставить исключение поднятый в оскорбительной нити. Вы можете найти пример, который использует этот API здесь. Хотя это код Python, одна и та же функция будет работать из вашего основного приложения.
Это решение немного менее безопасно, так как оно требует, чтобы код не улавливал исключение и оставался в работоспособном состоянии впоследствии.
Используйте ОС для завершения потока
Я не собираюсь заниматься этим, потому что он по своей сути небезопасен. Смотрите Есть ли способ убить Thread в Python? для объяснения причин.
Ответ 2
Если вам нужна контрольная лага и джиттер в какой-то системе реального времени, вставьте "StacklessPython" - Python с поддержкой co-подпрограмм. Используется в "Twisted Web Server".
Ответ 3
Я хотел иметь возможность прервать любой активно работающий блок кода Python, в том числе отменить бесконечный цикл или просто какой-нибудь долго работающий код. В моем приложении однопоточный код Python представлен и оценен. Запрос на прерывание может прийти в любое время. Этот вопрос и ответ имели решающее значение, помогая мне на самом деле достичь этого.
Я использую средний подход из ответа @Peter Brittain от июля 2016 года выше.
После запуска движка Python я получаю идентификатор потока, используя пакет threading
в коде Python. Я анализирую это в ac long value и сохраняю его.
Функция прерывания на самом деле довольно проста:
PyGILState_Ensure()
PyThreadState_SetAsyncExc(threadId, PyExc_Exception)
с использованием идентификатора потока, который я сохраняю ранее, и универсальный тип исключения
PyGILState_Release()
Так что спасибо как оригинальному вопросу, так и Питеру Бриттену!