Внимание. Весьма вероятно, что вы испортите вещи, если вы небрежно уничтожаете потоки или процессы как часть обычного потока выполнения. В случае кода Python except
и finally
не будут выполняться, у вас будут проблемы с памятью и синхронизацией (например, взаимоблокировки), открытые дескрипторы файлов и сокеты и т. Д. И т. Д. Killing - это решение вашей проблемы, так как гильотина может быть названа лекарством от перхоти.
Убийство нитку в Python
В общем вы не можете сделать это. Просто нет такого API. Вы можете найти some hacks для некоторых случаев, но в целом вы не можете. Единственный стабильный способ прекратить поток должен взаимодействовать с ним флагов, событий и т.д.
Force-стоп CherryPy процесс
При нажатии Ctrl +C в терминале, который владеет процессом CherryPy Python интерпретатор получает сигнал SIGINT
и выдает исключение KeyboardInterrupt
. Затем CherryPy приказывает своим рабочим потокам останавливаться и сообщает вам Ожидание окончания дочерних потоков .... Если рабочий поток заблокирован в коде пользователя, CherryPy будет ждать, пока он не будет выпущен.
Для принудительной остановки вы можете использовать общие kill -9 PID
, где PID
- это идентификатор процесса вашего процесса CherryPy. Иногда вы можете найти его с помощью любого монитора процесса. Или введите cherrypy.process.plugins.PIDFile
, чтобы написать файл pidfile.
Обработка потенциально не отвечающие задачи
В общем CherryPy представляет собой резьбовой сервер. Если в ваших задачах используется десяток секунд, вы можете легко запустить рабочие потоки. В таком случае фоновая задача может быть хорошей идеей (Celery, Rq) или, по крайней мере, с использованием cherrypy.process.plugins.BackgroundTask
. Но это, очевидно, заставляет вас перепроектировать вашу систему, сделать временное хранилище результатов, опросить опрос или нажать. Это добавляет сложности, поэтому решение должно быть принято взвешивать все плюсы и минусы.
Если вы можете ограничить выполнение на конце, которое выполняет обработку или расчет, вам лучше сделать это. Будь то база данных, или API-интерфейс веб-сервиса, или еще что-то, а затем просто обрабатывать исключение тайм-аута.
CherryPy вне коробки ожидания ответа
Существует ответ тайм-аут в CherryPy из коробки. Он управляется конфигурацией response.timeout
и cherrypy._TimeoutMonitor
, которая запускается в отдельном потоке и проверяет, был ли отсрочен ответ. Хотя на самом деле монитор устанавливает только атрибут, response.timed_out
, который позже просматривается в cherrypy._cprequest.Request.run
, и если это правда, то cherrypy.TimeoutError
поднят. Таким образом, исключение с учетом таймаута повышается после factum. Если ваш обработчик страницы блокируется в течение 30 секунд, вы получите исключение только через 30 секунд.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8,
# interval in seconds at which the timeout monitor runs
'engine.timeout_monitor.frequency' : 1
},
'/' : {
# the number of seconds to allow responses to run
'response.timeout' : 2
}
}
class App:
@cherrypy.expose
def index(self):
time.sleep(8)
print('after sleep')
return '<em>Timeout test</em>'
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
Принуждение ожидания ответа
Вы не можете убить нить, но вы можете убить процесс. Если вы не можете контролировать свои задачи каким-либо другим способом, вы можете завершить процесс выполнения и использовать монитор, чтобы убить его, когда у него закончилось время. Следующее демонстрирует эту идею.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import signal
import time
from multiprocessing import Process
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8,
# disable internal timeout monitor
'engine.timeout_monitor.on' : False,
# interval in seconds at which the timeout monitor runs
'engine.timeout_kill_monitor.frequency' : 1
},
'/' : {
# the number of seconds to allow responses to run
'response.timeout' : 2
}
}
class TimeoutKillMonitor(cherrypy._TimeoutMonitor):
def run(self):
cherrypy._TimeoutMonitor.run(self)
for request, response in self.servings:
if response.timed_out and hasattr(response, 'jobProcess'):
if response.jobProcess.is_alive():
os.kill(response.jobProcess.pid, signal.SIGKILL)
cherrypy.engine.timeout_kill_monitor = TimeoutKillMonitor(cherrypy.engine)
cherrypy.engine.timeout_kill_monitor.subscribe()
def externalJob():
time.sleep(8)
class App:
@cherrypy.expose
def index(self):
p = Process(target = externalJob)
p.start()
cherrypy.response.jobProcess = p
p.join()
# To determine whether your job process has been killed
# you can use ``killed = response.timed_out``. Reset it to
# ``False`` to avoid ``TimeoutError`` and response a failure
# state in other way.
return '<em>Result</em>'
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
Обратите внимание, что вы не можете использовать multiprocessing.Queue
или multiprocessing.Pipe
для связи с рабочим процессом, потому что, когда он был убит, доступ к любому из них заблокировать CherryPy нить. Вот цитата из документации Python для Process.terminate
.
Если этот метод используется, когда связанный с ним процесс использует трубу или очередь затем трубу или очередь несет ответственность повредиться и может стать непригодным для использования другим процессом. Аналогично, если процесс приобрел блокировку или семафор и т. Д., То завершение этого - , что может привести к взаимоблокировке других процессов.
Да, технически возможно заставить тайм-аут, но это обескураженный и подверженный ошибкам способ.