В Windows subprocess.Popen.terminate
вызывает win32's TerminalProcess
. Однако поведение, которое я вижу, заключается в том, что дочерние процессы процесса, который я пытаюсь завершить, все еще работают. Почему это? Как я могу гарантировать, что все дочерние процессы, запущенные процессом, будут убиты?подпроцесс: удаление дочерних процессов в Windows
ответ
С помощью psutil:
import psutil, os
def kill_proc_tree(pid, including_parent=True):
parent = psutil.Process(pid)
children = parent.children(recursive=True)
for child in children:
child.kill()
gone, still_alive = psutil.wait_procs(children, timeout=5)
if including_parent:
parent.kill()
parent.wait(5)
me = os.getpid()
kill_proc_tree(me)
Этот код выглядит так, как будто он убивает только детей первого уровня, а не внуков и т. Д. Может возникнуть проблема, если вы запускаете инструменты сборки или файлы .bat/.cmd с cmd.exe.Разве get_children() тоже означает внуков? – Macke
Точно. Чтобы включить внуков, вы должны указать «рекурсивный» вариант, как в parent.get_children (recursive = True) –
Это старый ответ, но это именно то, что я искал - кросс-платформенный способ убить все дочерние процессы. Все другие ответы, которые появились в Google, утверждают, что это невозможно. Спасибо за psutil! – Gilead
Это трудная задача. Windows фактически не хранит дерево процессов в пространстве процесса. Также невозможно прекратить процесс и указать, что его дети также должны умереть.
Один из способов использования этой задачи - рассказать обо всем дереве.
Другой способ сделать это (при условии, что вы порождая процесс верхнего уровня) заключается в использовании модуль, который был разработан с такого рода вещи в виду: http://benjamin.smedbergs.us/blog/tag/killableprocess/
Для того, чтобы сделать это в общем для себя , вы должны потратить некоторое время на создание списка назад. То есть, процесс хранит указатели на его PARENT, но родители, похоже, не хранят информацию о детях.
Итак, вы должны посмотреть на все процессы в системе (что действительно не так сложно), а затем вручную подключить точки непосредственно, посмотрев на родительское поле процесса. Затем вы выбираете дерево, которое вас интересует, и прогуливайте все это, убивая каждый узел поочередно, один за другим.
Обратите внимание, что Windows не обновляет родительский указатель ребенка, когда родительский объект умирает, поэтому в вашем дереве могут быть пробелы. Я не знаю, что вы можете с этим поделать.
Положите детей в NT Job object, то вы можете убить всех детей
Объекты работы выглядят как правильный путь для решения этой проблемы; слишком плохо, что это не интегрировано с модулем подпроцесса. –
Использование taskkill
с /T
флагом
p = subprocess.Popen(...)
<wait>
subprocess.call(['taskkill', '/F', '/T', '/PID', str(p.pid)])
Флаги для Taskkill имеет следующие документы:
TASKKILL [/S system [/U username [/P [password]]]]
{ [/FI filter] [/PID processid | /IM imagename] } [/T] [/F]
/S system Specifies the remote system to connect to.
/U [domain\]user Specifies the user context under which the
command should execute.
/P [password] Specifies the password for the given user
context. Prompts for input if omitted.
/FI filter Applies a filter to select a set of tasks.
Allows "*" to be used. ex. imagename eq acme*
/PID processid Specifies the PID of the process to be terminated.
Use TaskList to get the PID.
/IM imagename Specifies the image name of the process
to be terminated. Wildcard '*' can be used
to specify all tasks or image names.
/T Terminates the specified process and any
child processes which were started by it.
/F Specifies to forcefully terminate the process(es).
/? Displays this help message.
Или ходить по дереву процесса с помощью comtypes и WIN32API:
def killsubprocesses(parent_pid):
'''kill parent and all subprocess using COM/WMI and the win32api'''
log = logging.getLogger('killprocesses')
try:
import comtypes.client
except ImportError:
log.debug("comtypes not present, not killing subprocesses")
return
logging.getLogger('comtypes').setLevel(logging.INFO)
log.debug('Querying process tree...')
# get pid and subprocess pids for all alive processes
WMI = comtypes.client.CoGetObject('winmgmts:')
processes = WMI.InstancesOf('Win32_Process')
subprocess_pids = {} # parent pid -> list of child pids
for process in processes:
pid = process.Properties_('ProcessID').Value
parent = process.Properties_('ParentProcessId').Value
log.trace("process %i's parent is: %s" % (pid, parent))
subprocess_pids.setdefault(parent, []).append(pid)
subprocess_pids.setdefault(pid, [])
# find which we need to kill
log.debug('Determining subprocesses for pid %i...' % parent_pid)
processes_to_kill = []
parent_processes = [parent_pid]
while parent_processes:
current_pid = parent_processes.pop()
subps = subprocess_pids[current_pid]
log.debug("process %i children are: %s" % (current_pid, subps))
parent_processes.extend(subps)
processes_to_kill.extend(subps)
# kill the subprocess tree
if processes_to_kill:
log.info('Process pid %i spawned %i subprocesses, terminating them...' %
(parent_pid, len(processes_to_kill)))
else:
log.debug('Process pid %i had no subprocesses.' % parent_pid)
import ctypes
kernel32 = ctypes.windll.kernel32
for pid in processes_to_kill:
hProcess = kernel32.OpenProcess(PROCESS_TERMINATE, FALSE, pid)
if not hProcess:
log.warning('Unable to open process pid %i for termination' % pid)
else:
log.debug('Terminating pid %i' % pid)
kernel32.TerminateProcess(hProcess, 3)
kernel32.CloseHandle(hProcess)
Спасибо за это. – Speakeasys
Вот пример кода для метода объекта работы, но вместо subprocess
он использует win32api.CreateProcess
import win32process
import win32job
startup = win32process.STARTUPINFO()
(hProcess, hThread, processId, threadId) = win32process.CreateProcess(None, command, None, None, True, win32process.CREATE_BREAKAWAY_FROM_JOB, None, None, startup)
hJob = win32job.CreateJobObject(None, '')
extended_info = win32job.QueryInformationJobObject(hJob, win32job.JobObjectExtendedLimitInformation)
extended_info['BasicLimitInformation']['LimitFlags'] = win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
win32job.SetInformationJobObject(hJob, win32job.JobObjectExtendedLimitInformation, extended_info)
win32job.AssignProcessToJobObject(hJob, hProcess)
+1: это похоже на наиболее надежное решение, которое работает, даже если родительский процесс разбился. Вот [объяснение того, как это работает] (http://stackoverflow.com/a/23587108/4279) – jfs
У меня была такая же проблема и только процесс убийства через команду окна с возможностью для детского убийства «/ T»
def kill_command_windows(pid):
'''Run command via subprocess'''
dev_null = open(os.devnull, 'w')
command = ['TASKKILL', '/F', '/T', '/PID', str(pid)]
proc = subprocess.Popen(command, stdin=dev_null, stdout=sys.stdout, stderr=sys.stderr)
Я пытался убить процесс сборки Gradle, начатый с 'subprocess.Popen()'. Простой 'process.terminate()' или 'process.kill()' не работал на WIndows 7, но и опция «psutils» выше, но это было сделано. –
Какая версия Python и Windows? –
Здесь 2 варианта 1. Используйте этот exe как подпроцесс, который убивает деревья процесса для вас: http://www.latenighthacking.com/projects/2002/kill/ 2. Преобразуйте следующий код C в Python с помощью ctypes: http: //stackoverflow.com/questions/1173342/terminate-a-process-tree-c-for-windows – Unknown