Страницы

Поиск по вопросам

пятница, 24 января 2020 г.

Как убить процесс Popen('start', shell=True)

#python #windows #python_3x #subprocess


Привет!
Создаю процесс в питоне 

p = subprocess.Popen('start', shell=True)


Но вот убить его из кода не получается. Перепробовал несколько вариантов, но консоль
не закрывается

#1
p.kill()
#2
subprocess.Popen("TASKKILL /F /PID {pid} /T".format(pid=p.pid))
#3
p.terminate()

    


Ответы

Ответ 1



Методы .terminate(), .kill() у subprocess.Popen пытаются остановить только сам процесс: #!/usr/bin/env python3 import subprocess import sys import time start = time.monotonic() process = subprocess.Popen([sys.executable or 'python', '-c', 'import time; time.sleep(30)']) assert process.poll() is None # process is alive process.terminate() process.wait() assert (time.monotonic() - start) < 30 # exited before timeout assert process.poll() is not None # process is dead and reaped При этом дочерние процессы могут продолжать жить, пример. Вызвав Popen() с shell=True параметром, создаётся неявно процесс (cmd.exe, /bin/sh), который запускает переданную команду. Если это не встроенная/внутренняя команда, то у вас как минимум два процесса получается (сама оболочка плюс программа, которую она запустила). .kill() убивает саму оболочку, при этом дочерний процесс может продолжить жить. На *nix в этом случае можно попробовать запускать процесс в отдельной группе процессов и затем послать сигнал этой группе, чтобы все процессы завершились (похоже на то как Ctrl+C в баше работает): How to terminate a python subprocess launched with shell=True. На Windows, можно taskkill попробовать: from subprocess import Popen, check_call process = Popen('py -c "import time; time.sleep(30)"', shell=True) check_call("TASKKILL /F /PID {pid} /T".format(pid=process.pid)) /T аргумент говорит, что taskkill пытается убить как сам процесс так и любые дочерние процессы, которые он запустил. Используя /IM параметр, можно по имени процессы остановить. psutil модуль предоставляет переносимый способ убить дочерние процессы. Чтобы закрыть новое окно, созданное start командой, по завершению дочерней команды, можно явно /c параметр передать для cmd: D:\> start /wait "title" cmd /c batch.cmd Можно добавить /B к start, чтобы не создавалось новое окно. Если вы использовали start, чтобы в фоне, что-то выполнить, то в Питоне этого не нужно, просто уберите start (Popen() вызов не ждёт пока процесс завершится). Аналогично, если вам не нужно внутреннюю команду запустить, то можно без shell=True обойтись как правило. В качестве альтернативы явной остановки, можно запустить процессы таким образом, чтобы дочерние процессы автоматически уничтожались, когда родитель завершается: Python: how to kill child process(es) when parent dies? На Windows, это можно организовать присваиванием созданного родительского процесса к своему Job объекту.

Ответ 2



def killprocess(): ppidd = # любым способом получаем pid нужного нам процесса if ppidd: try: p = psutil.Process(ppidd) p.terminate() except psutil.NoSuchProcess: print ('oops loose process')

Ответ 3



Проблема в том, что start запускает процесс, который открывает окно и завершается, поэтому "убивать" возвращенный pid бессмысленно. Предлагаю 3 варианта: пробежаться по всем процессам с помощью psutil и найти, у какого был родителем указанный pid. запустить start "MySpecWindoe", а потом каким-то способом (каким, не пробовал) найти консоль с таким заголовком. у меня сработал такой код, запускал start C:\Python35\python.exe abc.py, может это решит задачу: import time import subprocess p = subprocess.Popen('cmd.exe') time.sleep(5) p.kill()

Комментариев нет:

Отправить комментарий