在Windows中终止使用shell = True启动的后台进程

时间:2018-10-03 15:39:27

标签: python windows cmd subprocess kill-process

我正在尝试从Python启动server to score PMML models in Java。完成计算后,我希望能够关闭该服务器(即终止进程)。我使用的是Windows10。但是,我发现它比我想象的要混乱的多。

首先,我像这样启动服务器:

p = subprocess.Popen('START /B java -jar openscoring-server-executable-1.4.3.jar',
                      shell=True)

我让它在后台运行,以便在用户运行脚本时不显示CMD窗口。为了实现这一点,我认为必须使用shell=True参数。

当我尝试使用此行终止进程时:

subprocess.call("TASKKILL /F /PID {pid} /T".format(pid=p.pid))

该进程仍在运行。实际上,p.pid返回的PID在任务管理器中甚至不存在。尝试使用this answer中提供的解决方案时,我已经确认了这一点:

def kill(proc_pid):
    process = psutil.Process(proc_pid)
    for proc in process.children(recursive=True):
        proc.kill()
    process.kill()

kill(p.pid)

这将返回异常NoSuchProcess: no process found with pid 5280

我可以通过任务管理器看到分配给我要杀死的进程的PID:

enter image description here

但是我不知道如何在Python中找到该PID来终止它。我在网站上找到的答案似乎不适用于在后台运行的进程。

编辑:

我认为如果可以使用shell=False运行命令,则可以解决此问题,但是由于START /B,我不知道如何执行该命令。这将返回错误:

p = subprocess.Popen(['START', '/B', 'java', '-jar openscoring-server-executable-1.4.3.jar'])

3 个答案:

答案 0 :(得分:0)

如果您找不到正确的PID,我可能有一个替代解决方案,可以利用您用来启动该过程的参数。这不是很好,因为您将遍历流程树直到找到命中为止,但是通过这种方式,它将确定地找到流程。

请记住,如果您有多个运行相同参数的进程,那么这可能不会总是返回正确的进程。

def process_get(*args):
    """Returns the process matching ``args``.
    Relies on ``args`` matching the argument list of the process to find.

    Args:
        *args: process arguments, e.g. ["java", "-jar", "somejar.jar"]

    Returns:
        :obj:`process`
    """
    import psutil
    for process in psutil.process_iter():
        try:
            if process.cmdline() == args:
                return process
        except psutil.AccessDenied:
            pass
    return None

答案 1 :(得分:0)

您可以在此处搜索您的应用并关闭。

import psutil
import os

ls = []
for p in psutil.process_iter():
    try:
        name = p.name()
        cmdline = p.cmdline()
        exe = p.exe()
        pid = p.pid
    except (psutil.AccessDenied, psutil.ZombieProcess):
        continue
    except psutil.NoSuchProcess:
        continue

答案 2 :(得分:0)

该行不起作用,因为您需要提供所有参数和确切的字符串。

if process.cmdline() == args:

我将其更改为还包括一些字符串和部分字符串

def process_get(*args):
        """Returns the process matching ``args``.
        Relies on ``args`` matching the argument list of the process to find.

        Args:
            *args: process arguments, e.g. ["java", "jar", "partialjarname"]

        Returns:
            :obj:`process`
        """
        import psutil
        for process in psutil.process_iter():
            try:
                if all(x in " ".join(process.cmdline()) for x in args):
                    return process
            except psutil.AccessDenied:
                pass
        return None