Kill background process launched with shell=True i

2019-08-22 06:11发布

问题:

I'm trying to launch from Python a server to score PMML models in Java. Once the calculations have been made, I want to be able to close that server (i.e. terminate the process). I'm on Windows 10. However, I'm finding it way more confusing than I thought it would be.

First I launch the server like this:

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

I make it run on the background so that the CMD window doesn't show up when the user runs the script. To make this possible I think that the shell=True parameter is necessary.

When I try to kill the process using this line:

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

The process is still running. In fact, the PID that p.pid returns doesn't even exist in the Task Manager. I've confirmed this when trying to use the solution provided in 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)

This returns the exception NoSuchProcess: no process found with pid 5280.

I can see via the Task Manager the PID assigned to the process I want to kill:

But I don't know how to find that PID within Python to terminate it. The answers I've found in the site don't seem to work with processes running in the background.

EDIT:

I think this could be solved if I was able to run the command with shell=False, but I don't know how to do it because of the START /B. This returns an error:

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

回答1:

You could just search for your app here and close.

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:

If you can't figure out the right PID, I might have an alternative solution leveraging the arguments you used to start the process. It's not as nice, since you will iterate over the process tree until you find a hit, but this way it will find the process for sure.

Just remember that this might not always return the correct process if you have multiple processes with the same argument running.

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