subprocess:在Windows中删除subprocess
在Windows上, subprocess.Popen.terminate
调用win32的TerminalProcess
。 但是,我看到的行为是我正在尝试终止的进程的subprocess仍在运行。 这是为什么? 如何确保stream程启动的所有subprocess都被终止?
通过使用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)
使用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)
这是一件很难的事情。 Windows实际上并没有在进程空间中存储进程树。 也不可能终止一个过程,并指定它的孩子也应该死亡。
一个办法是使用taskkill并告诉它怪怪整个树。
另一种方法(假设你正在产生顶级的过程)是使用一个开发出来的模块: http : //benjamin.smedbergs.us/blog/tag/killableprocess/
为了一般地为自己做这个,你必须花一些时间来build立这个列表。 也就是说,一个进程存储指向它的父项的指针,但父母似乎不存储关于子项的信息。
所以你必须查看系统中的所有进程(实际上并不那么难),然后通过查看父进程字段自己手动连接点。 然后,你select你感兴趣的树,并走完整个事情,依次杀死每个节点。
请注意,Windows不会在父母死亡时更新孩子的父指针,因此树中可能存在间隙。 我不知道你可以做些什么。
把孩子放在一个NT 工作对象中 ,然后你可以杀死所有的孩子
以下是Job对象方法的示例代码,但是使用win32api.CreateProcess
而不是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)
我有同样的问题,只是杀死通过Windows命令与子选项杀死“/ 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)