2015-01-06 8 views
9

In der Python 2.7 Dokumentation von Subprozess Modul, fand ich folgende Schnipsel:Ersetzen Shell Pipeline

p1 = Popen(["dmesg"], stdout=PIPE) 
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) 
p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits. 
output = p2.communicate()[0] 

Quelle: https://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline

Ich verstehe nicht, diese Zeile: p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits.

Hier p1 .stdout wird geschlossen. Wie erlaubt es p1, ein SIGPIPE zu erhalten, wenn p2 beendet wird?

+0

mögliches Duplikat von [Beispiel aus Python-Subprozessmodul erklären] (http://stackoverflow.com/questions/6046779/explain-example-from-python-subprocess-module) –

Antwort

4

Das Signal SIGPIPE wird normalerweise gesendet, wenn ein Prozess versucht, in eine Pipe zu schreiben, von der kein aktiver Prozess ausgeht. In der Shell-Pipeline Äquivalent Ihr Code-Snippet:

`dmesg | grep hda` 

Wenn der grep Prozess aus irgendeinem Grund beendet, bevor dmesg Ausgabe erfolgt schreibt, wird dmesg eine SIGPIPE erhalten und sich selbst beenden. Dies wäre das erwartete Verhalten für UNIX/Linux-Prozesse (http://en.wikipedia.org/wiki/Unix_signal).

dagegen in der Python-Implementierung subprocess verwenden, wenn p2 Ausfahrten vor p1 Ausgabe erfolgt zu erzeugen, die SIGPIPE nicht gesendet werden kann, da es eigentlich noch ein Prozess am Rohr suchen ist - der Python-Skript selbst (das was erstellt p1 und p2). Noch wichtiger ist, dass das Skript die Pipe betrachtet, aber nicht ihren Inhalt verbraucht - der Effekt ist, dass die Pipe unbegrenzt offen gehalten wird und p1 in der Schwebe bleibt.

Explizit p1.stdout Schließen lösen den Python-Skript aus dem Rohr und macht es so, dass kein anderes Verfahren als p2 ist am Rohr suchen - auf diese Weise, wenn p2 endet vor p1, bekommt p1 richtig das Signal selbst künstlich, ohne etwas zu Ende das Rohr offen halten. Hier

ist eine alternativ formuliert Erklärung: http://www.enricozini.org/2009/debian/python-pipes/

+0

"eine Pipe, von der kein aktiver Prozess ausgeht "und" noch ein Prozess, der auf die Pfeife schaut "sind nicht wirklich präzise Formulierungen. –

0

Vom docs:

The p1.stdout.close() call after starting the p2 is important in order for p1 to receive a SIGPIPE if p2 exits before p1. 

Das SIGPIPE Signal an einen Prozeß gesendet wird, wenn es um ein Rohr zu schreiben versucht, ohne einen Prozess zu dem angeschlossenen anderes Ende. Wenn p2 mit stdin=p1.stdout erstellt wird, sind zwei Prozesse mit der Pipe verbunden: p1.stdout: der Eltern-Python-Prozess und p2. Selbst wenn p2 vorzeitig geschlossen wird, läuft der Elternprozess immer noch, daher wird das Signal SIGPIPE nicht gesendet. p1.stdout.close() schließt p1.stdout im Parent/Caller-Prozess, wodurch dmesg als einziger Prozess mit diesem Dateideskriptor geöffnet bleibt.

Mit anderen Worten, wenn es dann keine p1.stdout.close() ist: bleibt

  • p1.stdout offen in dem übergeordneten Prozess. Wenn p2 austritt (d. H. Es gibt niemand, um p1.stdout zu lesen), weiß p1 nicht, dass niemand p1.stdout liest, und schreibt weiterhin in p1.stdout, bis der entsprechende OS-Pipe-Pufferspeicher voll ist.
  • für den Fall, dass p2 vorzeitig beendet wird, p1.stdout wäre immer noch im übergeordneten Prozess geöffnet, damit SIGPIPE nicht generiert wird.
2

eine hoffentlich systematische Erklärung:

  • Ein Rohr ist eine Instanz durch das Betriebssystem verwaltet. Es hat ein einzelnes Leseende und ein einzelnes Schreibende.
  • Beide Enden können durch mehrere Prozesse geöffnet werden. Es gibt aber immer noch nur eine Pfeife. Das heißt, mehrere Prozesse können sich dieselbe Leitung teilen.
  • Ein Prozess, der eines der Enden geöffnet hat, enthält ein entsprechendes Dateihandle. Der Prozess kann close() es wieder aktiv! Wenn ein Prozess beendet wird, schließt das Betriebssystem das entsprechende Dateihandle für Sie.
  • Alle beteiligten Prozesse können close() ihr Dateihandle, das das Leseende der Pipe darstellt. Daran ist nichts falsch, das ist eine vollkommen gute Situation.
  • Wenn nun ein Prozess Daten auf das Schreibende der Pipe schreibt und das Leseende nicht mehr geöffnet wird (kein Prozess enthält eine offene Dateikennung für das Leseende), sendet ein POSIX-kompatibles Betriebssystem ein SIGPIPE Signal an die schreiben Prozess für sie zu wissen, dass es kein Lesegerät mehr gibt.

Dies ist der Standard-Mechanismus, mit dem das empfangende Programm kann implizit das sendende Programm sagen, dass es das Lesen gestoppt wurde. Haben Sie sich jemals gefragt, ob

cat bigfile | head -n5 

liest eigentlich die gesamte bigfile? Nein, nicht, weil cat ein SIGPIPE Signal abfragt, sobald head beendet wird (nach dem Lesen von 5 Zeilen von Stdin). Die wichtige Sache zu schätzen: cat wurde entwickelt, um tatsächlich reagieren zu SIGPIPE (das ist eine wichtige technische Entscheidung;)): Es hört auf, die Datei zu lesen und beendet. Andere Programme ignorieren SIGPIPE (absichtlich behandeln sie diese Situation alleine - das ist in Netzwerkanwendungen üblich).

Wenn Sie das Leseende der Pipe in Ihrem Kontrollprozess geöffnet lassen, deaktivieren Sie den beschriebenen Mechanismus. dmesg kann nicht bemerken, dass grep beendet wurde.

Allerdings ist Ihr Beispiel eigentlich kein guter. grep hda wird der gesamte Eingang lesen. dmesg ist der Prozess, der zuerst beendet wird.

Verwandte Themen