Как закрыть процесс через python
Перейти к содержимому

Как закрыть процесс через python

  • автор:

Python Multiprocessing изящное завершение работы в правильном порядке

Сначала останавливается процесс worker(), затем данные процесса result_queue() промываются и останавливаются.

16 июня 2021 Обновленный 17 июня 2021

post main image

https://unsplash.com/@marcella_mlk

Для нового проекта мне понадобился процесс deamon, который должен выполнять множество более или менее одинаковых операций на различных ресурсах. В данном случае операция связана с IO, и я решил эту проблему с помощью ThreadPoolExecutor. Пока все хорошо.

Далее я хотел хранить результаты в файлах. Конечно, мы используем очередь для связи между процессами. Процесс worker() использует q.put() для добавления элементов в очередь, а процесс result_queue() использует q.get() для получения элементов из очереди.

Мой процесс result_queue() также буферизирует полученные результаты. Как только достигается порог, все результаты сразу записываются в файл.

И вот в чем проблема. Когда вы нажимаете CTRL-C или посылаете сигнал SIGTERM , то процессы резко завершаются. Это означает:

  • Ресурсы, к которым обращался worker() , могут быть оставлены в плохом состоянии.
  • result_queue() может содержать много результатов, которые не будут сохранены.

Нехорошо! Ниже я покажу, как я решил эту проблему. Как всегда, я использую Ubuntu (20.04).

Использование событий для остановки дочерних процессов

Страницы в интернете о Python и Multiprocessing часто сбивают с толку, в основном потому, что многие ссылаются на Python2. Хорошо то, что вы вынуждены читать официальную документацию .

Существует два способа, с помощью которых процессы могут взаимодействовать (надежно) друг с другом:

В данном случае, чтобы остановить процессы, мы используем события. Мы называем наши события stop-events, потому что они требуют остановки дочернего процесса. Это работает следующим образом:

  1. Создайте событие (объект)
  2. Передайте событие в качестве параметра при запуске дочернего процесса.
  3. В дочернем процессе: проверьте событие и остановитесь, если событие ‘is_set()’
  4. В главном процессе: ‘set()’ событие, если дочерний процесс должен быть остановлен.

Замените обработчики для SIGINT / SIGTERM

Вот трюк, который заставляет все работать:

Когда вы порождаете дочерний процесс, этот процесс также наследует обработчики сигналов от родительского.

Мы не хотим, чтобы наши дочерние процессы реагировали на CTRL-C (сигнал SIGINT ) или SIGTERM . Вместо этого мы хотим, чтобы главный процесс решал, как будут остановлены дочерние процессы. Это означает, что мы должны:

  1. Заменить обработчики SIGINT и SIGTERM для дочерних процессов на фиктивные обработчики. Эти обработчики ничего не делают, что означает, что дочерние процессы не завершаются по этим сигналам.
  2. Замените обработчики SIGINT и SIGTERM главного процесса на нашу собственную версию. Эти обработчики сообщают главному процессу, что он должен выключиться. Это делается с помощью события остановки главного процесса (объект)

При такой схеме главный процесс проверяет событие main stop. Если ‘is_set()’, он использует ‘set()’, чтобы сообщить дочернему процессу X о необходимости остановиться. Поскольку мы можем передавать события остановки всем дочерним процессам, главный процесс имеет полный контроль. Он может дождаться остановки дочернего процесса, прежде чем остановить другой дочерний процесс.

Код

Есть три процесса:

  • main()
  • (дочерний) worker(), может иметь несколько потоков
  • (дочерний) result_queue()

Когда поток worker() завершает работу, он отправляет результат в result_queue(). Для изящной остановки мы должны сначала попросить процесс worker() остановиться, а как только он остановился, мы должны попросить остановиться процесс result_queue() .

Думаю, код несложно прочитать. После запуска дочерних процессов главный процесс в цикле проверяет, не запрошена ли остановка.

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

# procsig.py import logging import multiprocessing import os import signal import sys import time def init_logger(): logger_format = "%(asctime)s %(levelname)-8.8s [%(funcName)24s():%(lineno)-3s] %(message)s" formatter = logging.Formatter(logger_format) logger = logging.getLogger() logger.setLevel(logging.DEBUG) handler = logging.StreamHandler() handler.setFormatter(formatter) logger.addHandler(handler) return logger logger = init_logger() # main sigint/sigterm handlers main_stop_event = multiprocessing.Event() def main_sigint_handler(signum, frame): logger.debug('') main_stop_event.set() def main_sigterm_handler(signum, frame): logger.debug('') main_stop_event.set() # children sigint/sigterm handlers, let main process handle this def children_sigint_handler(signum, frame): logger.debug('') def children_sigterm_handler(signum, frame): logger.debug('') def worker(rq, stop_event): i = 0 while True: if stop_event.is_set(): break logger.debug('worker: <>'.format(i)) time.sleep(1) i += 1 logger.debug('worker STOPPING . ') time.sleep(1) logger.debug('worker STOPPED') def result_queue(rq, stop_event): i = 0 while True: if stop_event.is_set(): break logger.debug('result_queue: <>'.format(i)) time.sleep(1) i += 1 logger.debug('result_queue: STOPPING') time.sleep(1) logger.debug('result_queue: STOPPED') def main(): # events global main_stop_event worker_stop_event = multiprocessing.Event() result_queue_stop_event = multiprocessing.Event() # setup result queue rq = multiprocessing.Queue() # children: capture sigint/sigterm signal.signal(signal.SIGINT, children_sigint_handler) signal.signal(signal.SIGTERM, children_sigterm_handler) # start worker worker_proc = multiprocessing.Process( name='worker', target=worker, kwargs=, ) worker_proc.daemon = True worker_proc.start() # start result_queue result_queue_proc = multiprocessing.Process( name='result_queue', target=result_queue, kwargs=, ) result_queue_proc.daemon = True result_queue_proc.start() # main: capture sigint/sigterm signal.signal(signal.SIGINT, main_sigint_handler) signal.signal(signal.SIGTERM, main_sigterm_handler) child_procs = [worker_proc, result_queue_proc] worker_stop_sent = False result_queue_stop_sent = False max_allowed_shutdown_seconds = 10 shutdown_et = None keep_running = True while keep_running: if shutdown_et is not None and shutdown_et < int(time.time()): logger.debug('Forced shutdown . ') break run_count = 0 for p in child_procs: logger.debug('[P> - <> - <> - <>'.format(p.name, p.pid, p.is_alive(), p.exitcode)) if p.is_alive(): run_count += 1 # send 'stop' to result_queue()? if p.pid == worker_proc.pid and not p.is_alive() and not result_queue_stop_sent: logger.debug('Sending stop to result_queue . ') result_queue_stop_event.set() result_queue_stop_sent = True # send 'stop' to worker()? if main_stop_event.is_set() and not worker_stop_sent: logger.debug('Sending stop to worker . ') worker_stop_event.set() worker_stop_sent = True shutdown_et = int(time.time()) + max_allowed_shutdown_seconds time.sleep(1) if run_count == 0: keep_running = False logger.debug('terminating children . ') try: worker_proc.terminate() result_queue_proc.terminate() worker_proc.kill() result_queue_proc.terminate() except Exception as e: # who cares logger.debug('Exception <>, e = <>'.format(type(e).__name__, e)) logger.debug('Done') if __name__=='__main__': main()

Чтобы проверить это, нажмите CTRL-C, или откройте другое окно терминала и завершите этот процесс:

pkill -f procsig

Результат журнала

Вы можете попробовать это сами, ниже я покажу, что будет выведено в консоль. В ’19:28:37′ я нажал CTRL-C. Сразу же вызываются обработчики сигналов. Процесс main() посылает сообщение об остановке процессу worker() , используя ‘set()’. Как только процесс worker() остановился, проверив ‘is_alive()’, процессу result_queue() посылается сообщение об остановке.

2021-06-16 19:28:34,238 DEBUG [ worker():182] worker: 6 2021-06-16 19:28:35,239 DEBUG [ worker():182] worker: 7 2021-06-16 19:28:35,239 DEBUG [ result_queue():197] result_queue: 7 2021-06-16 19:28:35,239 DEBUG [ main():259] [P> worker - 465189 - True - None 2021-06-16 19:28:35,239 DEBUG [ main():259] [P> result_queue - 465190 - True - None 2021-06-16 19:28:36,239 DEBUG [ worker():182] worker: 8 2021-06-16 19:28:36,240 DEBUG [ result_queue():197] result_queue: 8 2021-06-16 19:28:36,240 DEBUG [ main():259] [P> worker - 465189 - True - None 2021-06-16 19:28:36,241 DEBUG [ main():259] [P> result_queue - 465190 - True - None 2021-06-16 19:28:37,239 DEBUG [ worker():182] worker: 9 2021-06-16 19:28:37,241 DEBUG [ result_queue():197] result_queue: 9 2021-06-16 19:28:37,242 DEBUG [ main():259] [P> worker - 465189 - True - None 2021-06-16 19:28:37,242 DEBUG [ main():259] [P> result_queue - 465190 - True - None ^C2021-06-16 19:28:37,598 DEBUG [ children_sigint_handler():170] 2021-06-16 19:28:37,598 DEBUG [ children_sigint_handler():170] 2021-06-16 19:28:37,598 DEBUG [ main_sigint_handler():160] 2021-06-16 19:28:38,240 DEBUG [ worker():182] worker: 10 2021-06-16 19:28:38,242 DEBUG [ result_queue():197] result_queue: 10 2021-06-16 19:28:38,243 DEBUG [ main():259] [P> worker - 465189 - True - None 2021-06-16 19:28:38,243 DEBUG [ main():259] [P> result_queue - 465190 - True - None 2021-06-16 19:28:38,243 DEBUG [ main():271] Sending stop to worker . 2021-06-16 19:28:39,241 DEBUG [ worker():186] worker STOPPING . 2021-06-16 19:28:39,243 DEBUG [ result_queue():197] result_queue: 11 2021-06-16 19:28:39,244 DEBUG [ main():259] [P> worker - 465189 - True - None 2021-06-16 19:28:39,244 DEBUG [ main():259] [P> result_queue - 465190 - True - None 2021-06-16 19:28:40,242 DEBUG [ worker():188] worker STOPPED 2021-06-16 19:28:40,244 DEBUG [ result_queue():197] result_queue: 12 2021-06-16 19:28:40,245 DEBUG [ main():259] [P> worker - 465189 - False - 0 2021-06-16 19:28:40,245 DEBUG [ main():265] Sending stop to result_queue . 2021-06-16 19:28:40,246 DEBUG [ main():259] [P> result_queue - 465190 - True - None 2021-06-16 19:28:41,246 DEBUG [ result_queue():201] result_queue: STOPPING 2021-06-16 19:28:41,247 DEBUG [ main():259] [P> worker - 465189 - False - 0 2021-06-16 19:28:41,247 DEBUG [ main():259] [P> result_queue - 465190 - True - None 2021-06-16 19:28:42,247 DEBUG [ result_queue():203] result_queue: STOPPED 2021-06-16 19:28:42,248 DEBUG [ main():259] [P> worker - 465189 - False - 0 2021-06-16 19:28:42,248 DEBUG [ main():259] [P> result_queue - 465190 - False - 0 2021-06-16 19:28:43,249 DEBUG [ main():280] terminating children . 2021-06-16 19:28:43,249 DEBUG [ main():290] Done

Резюме

Я искал способ изящной остановки процессов с помощью Python Multiprocessing , а также хотел контролировать порядок остановки процессов. Я решил эту проблему, используя события и заменив обработчики сигналов. Это дает мне полный контроль над главным процессом. Теперь я могу попросить остановить процесс B после остановки процесса A.

Как завершить процесс python multiprocess

у меня есть процесс хочу по его названию( не по PID ) завершить его, как это реализовать?

Отслеживать

задан 2 июн 2021 в 13:17

Артём Новокеков Артём Новокеков

27 3 3 бронзовых знака

Покажите пожалуйста в вопросе, где у вас есть процесс?

2 июн 2021 в 13:50

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

непонятно что имеется виду, если это рукотворный multiprocess процесс, то соответственно есть и его объект, у которого есть имя и метод terminate, берете объект процесса, сравниваете его имя, и при необходимости завершаете через terminate

import multiprocessing, time, random def test(s, m=500): while m > 0: print(f' = ') m -= 1 time.sleep(.5) if __name__ == '__main__': multiprocessing.freeze_support() count = 3 prcss = [multiprocessing.Process(name=f'test_', target=test, args=[f'run_test_']) for r in range(count)] pnames = [p.name for p in prcss] # имена процессов for p in prcss: p.start() while prcss: for p in prcss: name = random.choice(pnames) if p.name == name: # завершить по его названию p.terminate() prcss.remove(p) print(f'KILL 

') break time.sleep(1)

если это сторонний процесс, то через psutil

import psutil for proc in psutil.process_iter(): if proc.name() == 'test process': # завершить по его названию proc.kill() break 

Как завершить процесс python?

Сейчас надо внести изменения в один из файлов но не могу завершить работу бота телеграм. После ввода команды в консоль он продолжает работать ((
какие есть еще команды для убийства процесса?

  • Вопрос задан более двух лет назад
  • 1659 просмотров

Комментировать
Решения вопроса 0
Ответы на вопрос 1

vabka

Токсичный шарпист
Находишь нужный процесс через ps и убиваешь через обычный kill -9
Ответ написан более двух лет назад
EVG82 @EVG82 Автор вопроса

этой командой он вывел процессы не относящиеся к моей конкретной директории.
а через Putty дал так

Last login: Mon Feb 28 05:59:38 2022 from 178.166.210.107
root@templ-ubuntu-2004:~# cd /root/bots/botdelete_test
root@templ-ubuntu-2004:~/bots/botdelete_test# ps
PID TTY TIME CMD
1408 pts/0 00:00:00 bash
1417 pts/0 00:00:00 ps
root@templ-ubuntu-2004:~/bots/botdelete_test#

или я что то не так делаю?

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

EVG82, ps aux | grep python
Затем, берем нужный pid и делаем kill -9
EVG82 @EVG82 Автор вопроса

А почему у процесса постоянно pid меняется?
Может на это влиять автозапуск процесса при сбоях на сервере?

621e4e1a30505819293953.jpeg

в данном случае грохнуть надо

root 2845 1 7 19:45 ? 00:00:00 /usr/bin/python3 /root/bots/botdelete_test/main.py

и каждый раз новый номер ) а у других нормально?

Vindicar

EVG82, ну вот тебе и ответ. Ты его таки грохаешь. но процесс почему-то перезапускается. Ты его случаем в system.d не запихивал, или еще в какую мониторилку?

EVG82 @EVG82 Автор вопроса

Vindicar, ну да.
но я в самом боте переименовываю файл bot.service и тоже самое.
то есть надо убрать из system.d ?

Vindicar

EVG82, эмм, ты после того как меняешь .service файл, перезагружаешь параметры systemd? У него вроде есть суб-команда daemon-reload.

Python, как правильно завершить процесс .exe?

Теперь через определённое время их нужно завершить, например третий профиль, потом пятый, первый и т.д
С этим я так и не разобрался.
Разобрался как убить все процессы firefox.exe:

os.system(«taskkill /im firefox.exe»)

Но при следующем запуске, firefox пишет что не корректно была завершена работа и просит запуститься в безопасном режиме.
При alt+f4 не ругается на некорректное завершение работы.
Вопрос в том как правильно завершить что бы он не ругался?
А ещё лучше как правильно завершить определённый профиль?

  • Вопрос задан более двух лет назад
  • 4052 просмотра

Комментировать
Решения вопроса 1

HemulGM

Hemul GM @HemulGM Куратор тега Python
Delphi Developer, сис. админ
Отправить сообщение приложению о закрытии через WinAPI
Ответ написан более двух лет назад
Нравится 1 2 комментария
XXocTT Python @XXocTT Автор вопроса
Не совсем пойму как. Гугл особо инфы не даёт, возможно я задаю вопрос не правильно

HemulGM

Hemul GM @HemulGM Куратор тега Python

Пётр Питаев, PostMessage(H, WM_QUIT, 0, 0);
H — Handle приложения (или окна)
PostMessage — это метод WInApi, гугли.

Ответы на вопрос 1

yupiter7575

Yupiter7575 @yupiter7575
Python программист

os.system(«taskkill /im firefox.exe»)

Это плохая практика. Намного лучше делать так:

import subprocess as sp sp.Popen('taskkill /im firefox.exe /f')

Если вы запускаете через интерпретатор пайтона, если же у вас упакованный .py файл, то лучше сделать так:

import psutil #pip isntall psutil for proc in psutil.process_iter(): if proc.name() == 'firefox.exe': proc.terminate()

Ответ написан более двух лет назад
XXocTT Python @XXocTT Автор вопроса
Спасибо. Но сожалению я получаю то же самое сообщение

выдает такую ошибку при установку psutil

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *