Domanda

Sto lanciando un sottoprocesso con il seguente comando:

p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)

Tuttavia, quando provo ad uccidere utilizzando:

p.terminate()

o

p.kill()

Il comando continua a funzionare in background, quindi mi chiedevo come posso davvero terminare il processo.

Si noti che quando ho eseguito il comando con:

p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)

Si fa terminare con successo al momento del rilascio del p.terminate().

È stato utile?

Soluzione

Usa un gruppo di processi in modo da consentire l'invio di un segnale a tutto il processo nei gruppi . Per questo, si dovrebbe allegare un id di sessione per il processo padre della processi generato / figlio, che è un guscio nel tuo caso. In questo modo sarà il capogruppo dei processi. Così ora, quando un segnale viene inviato al leader del gruppo di processi, è trasmesso a tutti i processi figlio di questo gruppo.

Ecco il codice:

import os
import signal
import subprocess

# The os.setsid() is passed in the argument preexec_fn so
# it's run after the fork() and before  exec() to run the shell.
pro = subprocess.Popen(cmd, stdout=subprocess.PIPE, 
                       shell=True, preexec_fn=os.setsid) 

os.killpg(os.getpgid(pro.pid), signal.SIGTERM)  # Send the signal to all the process groups

Altri suggerimenti

p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
p.kill()

estremità p.kill() per uccidere il processo guscio e cmd è ancora in esecuzione.

Ho trovato una vantaggiosa risolvere questo problema:

p = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, shell=True)

Questo farà sì che cmd per ereditare il processo shell, invece di avere il lancio di shell un processo figlio, che non vengono uccisi. p.pid sarà l'id del processo cmd poi.

p.kill() dovrebbe funzionare.

Non so che effetto questo avrà sul tubo però.

Se è possibile utilizzare psutil , quindi Questo funziona perfettamente:

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)

ho potuto farlo utilizzando

from subprocess import Popen

process = Popen(command, shell=True)
Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))

ha ucciso il cmd.exe e il programma che ho dato il comando per.

(In Windows)

Quando shell=True la shell è il processo figlio, ei comandi sono i suoi figli. Quindi, qualsiasi SIGTERM o SIGKILL uccideranno il guscio, ma non i suoi processi figli, e non mi ricordo un buon modo per farlo. Il modo migliore che posso pensare è quello di utilizzare shell=False, altrimenti quando si uccide il processo di shell genitore, lascerà un processo shell defunta.

Niente di tutto questo risponde lavorato per me in modo da Im lasciando il codice che ha funzionato. Nel mio caso, anche dopo aver ucciso il processo con .kill() e ottenere un codice di ritorno .poll() il processo non è terminato.

A seguito della subprocess.Popen documentazione :

"... al fine di pulitura correttamente un'applicazione ben educati dovrebbe uccidere la comunicazione processo figlio e la finitura ..."

proc = subprocess.Popen(...)
try:
    outs, errs = proc.communicate(timeout=15)
except TimeoutExpired:
    proc.kill()
    outs, errs = proc.communicate()

Nel mio caso mi mancava il proc.communicate() dopo aver chiamato proc.kill(). Questo pulisce il processo di stdin, stdout ... e fa terminare il processo.

Come Sai, ha detto, il guscio è il bambino, in modo da segnali vengono intercettati da essa - migliore modo che ho trovato è quello di utilizzare shell = False e l'uso shlex per dividere la linea di comando:

if isinstance(command, unicode):
    cmd = command.encode('utf8')
args = shlex.split(cmd)

p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

p.kill Poi () e p.terminate () dovrebbe funzionare come ci si aspetta.

quello che mi sento come potremmo usare:

import os
import signal
import subprocess
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)

os.killpg(os.getpgid(pro.pid), signal.SIGINT)

questo non uccidere tutti il ??vostro compito, ma il processo con il p.pid

So che questa è una vecchia questione, ma questo può aiutare chi cerca un metodo diverso. Questo è quello che uso su Windows per uccidere i processi che ho chiamato.

si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
subprocess.call(["taskkill", "/IM", "robocopy.exe", "/T", "/F"], startupinfo=si)

/ IM è il nome dell'immagine, si può anche fare / PID se si desidera. / T uccide il processo così come i processi figlio. / Forza F termina esso. si, come ho impostato, è come si esegue questa operazione senza mostrare una finestra CMD. Questo codice viene utilizzato in Python 3.

Invia il segnale a tutti i processi nel gruppo

    self.proc = Popen(commands, 
            stdout=PIPE, 
            stderr=STDOUT, 
            universal_newlines=True, 
            preexec_fn=os.setsid)

    os.killpg(os.getpgid(self.proc.pid), signal.SIGHUP)
    os.killpg(os.getpgid(self.proc.pid), signal.SIGTERM)

Non ho visto questo menzionato qui, quindi sto mettendo là fuori nel caso qualcuno esigenze IT. Se tutto quello che vogliamo fare è assicurarsi che il sottoprocesso termina con successo, si potrebbe mettere in un contesto manager. Per esempio, ho voluto che la mia stampante standard di stampare un'immagine fuori e utilizzando il gestore contesto assicurato che il sottoprocesso terminato.

import subprocess

with open(filename,'rb') as f:
    img=f.read()
with subprocess.Popen("/usr/bin/lpr", stdin=subprocess.PIPE) as lpr:
    lpr.stdin.write(img)
print('Printed image...')

Credo che questo metodo è anche cross-platform.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top