2014-02-21 2 views
34

Ich bin völlig zwischen subprocess.call(), subprocess.Popen(), subprocess.check_call() verwirrt.blockieren und nicht blockieren Unterprozessaufrufe

Welche blockiert und welche nicht?

Was ich meine zu sagen ist, wenn ich subprocess.Popen() verwenden, ob der übergeordnete Prozess auf den untergeordneten Prozess return/10 wartet, bevor es auf seiner Ausführung bleibt.

Wie wirkt sich shell=True auf diese Anrufe aus?

+0

haben Sie versucht, 'subprocess.call ([cmd, params, &])' '? –

Antwort

52

Popen ist nicht blockierend. call und check_call blockieren. Sie können die Popen Instanz blockieren, indem Sie die Methode wait oder communicate aufrufen. Wenn Sie in the source code suchen, sehen Sie call Anrufe Popen(...).wait(), weshalb es blockiert. check_call ruft call, weshalb es auch blockiert.

Streng genommen ist shell=True orthogonal zum Problem der Blockierung. shell=True bewirkt jedoch, dass Python eine Shell ausführt und dann den Befehl in der Shell ausführt. Wenn Sie einen blockierenden Anruf verwenden, wird der Anruf zurückgegeben, wenn die Shell beendet wird. Da die Shell einen Unterprozess zur Ausführung des Befehls erzeugen kann, endet die Shell möglicherweise vor dem erzeugten Unterprozess. Zum Beispiel

import subprocess 
import time 

proc = subprocess.Popen('ls -lRa /', shell=True) 
time.sleep(3) 
proc.terminate() 
proc.wait() 

hier zwei Prozesse hervorgebracht: Popen laicht ein subprocess des Shell ausgeführt wird. Die Shell wiederum erzeugt einen Subprozess mit der Nummer ls. proc.terminate() tötet die Shell, aber der Subprozess, der ls ausgeführt wird, bleibt. (Das zeigt sich an der umfangreichen Ausgabe, selbst nachdem das Python-Skript beendet wurde. Bereiten Sie sich darauf vor, die ls mit pkill ls zu töten.)

+4

['start_new_session = True' oder seine Analoga] (http://stackoverflow.com/a/13256908/4279) ermöglicht das Beenden des gesamten Prozessbaums auf einmal. Siehe [So beenden Sie einen Python-Subprozess, der mit shell = True gestartet wurde] (http://stackoverflow.com/q/4789837/4279) – jfs

+0

Vielen Dank, Ihre Antwort hat mir sehr geholfen. P.S. 'proc = subprocess.Popen (['/ run_python.py', '-n', '10'], shell = True)' unterscheidet sich von dem 'proc = subprocess.Popen (" run_python.py -n 10 ", shell = True) 'Nur der letzte funktioniert, wenn der Befehl über einem Python-Skript erstellt wird. – dotslash

+2

@dotslash: 'shell = True' kann ein [Sicherheitsrisiko] (https://docs.python.org/2/library/subprocess.html#using-the-subprocess-module) sein, wenn der Befehl von einer Benutzereingabe kommt . Daher ist es besser, wenn möglich 'shell = False' zu ​​verwenden. Mit 'shell = False' geben Sie den Befehl und seine Argumente in einer Liste an:' proc = subprocess.Popen (['/ run_python.py', '-n', '10'], shell = False) '. – unutbu