Я запускаю подпроцесс следующей командой:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
Однако, когда я пытаюсь его завершить, используя:
p.terminate()
или же:
p.kill()
команда продолжает работать в фоновом режиме, поэтому мне было интересно, как я могу завершить процесс.
Обратите внимание, что, когда я запускаю команду с:
p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
он действительно завершается успешно при вызове p.terminate().
Ответ 1
Используйте группу процессов, чтобы разрешить отправку сигнала всем процессам в группах. Для этого вы должны прикрепить идентификатор сеанса к родительскому процессу порожденных/дочерних процессов, который в вашем случае является оболочкой. Это сделает его лидером группы процессов. Итак, теперь, когда сигнал отправляется лидеру группы процессов, он передается всем дочерним процессам этой группы.
Вот код:
import os
import signal
import subprocess
# Команда os.setsid() передается в аргументе preexec_fn, поэтому.
# она выполняется после fork() и перед exec() для запуска оболочки.
pro = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
os.killpg(os.getpgid(pro.pid), signal.SIGTERM) # Отправляет сигнал всем группам процессов
Ответ 2
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
p.kill()
p.kill() заканчивает выполнение и завершает процесс оболочки, но cmd все еще работает.
Я нашел удобное решение:
p = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, shell=True)
Это заставит cmd унаследовать процесс оболочки вместо того, чтобы оболочка запускала дочерний процесс, который не завершается. p.pid тогда будет идентификатором вашего процесса cmd, и p.kill() должен сработать.
Ответ 3
Если вы можете использовать psutil, это отлично работает:
import subprocess
import psutil
def kill(proc_pid):
process = psutil.Process(proc_pid)
for proc in process.children(recursive=True):
proc.kill()
process.kill()
proc = subprocess.Popen(["infinite_app", "param"], shell=True)
try:
proc.wait(timeout=3)
except subprocess.TimeoutExpired:
kill(proc.pid)
Ответ 4
Я мог бы сделать это, используя:
from subprocess import Popen
process = Popen(command, shell=True)
Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))
Это завершает cmd.exe программу, для которой дается эта команда (в Windows).
Ответ 5
Ни один из ответов у меня не сработал, поэтому я даю код, который действительно работает. В моем случае даже после завершения процесса .kill() и получения .poll() кода возврата, процесс не завершился.
Следуя subprocess.Popen из документации:
«... для правильной очистки приложение с допустимым поведением должно завершить дочерний процесс и завершить обмен данными ...»
proc = subprocess.Popen(...)
try:
outs, errs = proc.communicate(timeout=15)
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()
В моем случае мне не хватало proc.communicate() после вызова proc.kill(). Это очищает процесс stdin, stdout ... и завершает процесс.
Python