Wie schließe ich das stdout-Rohr, wenn das Töten ein Prozess mit Python subprocess Popen gestartet?

StackOverflow https://stackoverflow.com/questions/1624254

Frage

Ich frage mich, ob es möglich ist, das Verbindungsrohr herunterzufahren, wenn das Töten eines Teilprozesses in einem anderen Thread gestartet. Wenn ich nicht nennen kommunizieren () dann töten () wird wie erwartet, den Prozess nach einer Sekunde beendet wird anstelle von fünf Jahren.

Ich fand eine Diskussion über ein ähnliches Problem hier , aber ich habe keine wirklichen Antworten. Ich gehe davon aus, dass ich entweder das Rohr schließen können, oder explizit die Unter subprocess zu töten (die „Schlaf“ im Beispiel) und töten, dass das Rohr zu entsperren.

Ich habe auch versucht, die Antwort sich auf SO zu finden, aber ich fand nur diese und diese und this , die nicht direkt dieses Problem lösen, soweit ich das beurteilen kann ( ?).

Also das, was ich tun möchte, ist in der Lage sein, einen Befehl in einem zweiten Thread ausgeführt und all seine Ausgabe, aber die Lage sein, sie sofort zu töten, wenn ich so wünschen. Ich konnte über eine Datei und Schwanz gehe, dass oder ähnliches, aber ich denke, es sollte ein besserer Weg, dies zu tun?

import subprocess, time
from threading import Thread

process = None

def executeCommand(command, runCommand):
    Thread(target=runCommand, args=(command,)).start()

def runCommand(command):
    global process
    args = command.strip().split()
    process = subprocess.Popen(args, shell=False, stdout=subprocess.PIPE)

    for line in process.communicate():
        if line:
            print "process:", line,

if __name__ == '__main__':
    executeCommand("./ascript.sh", runCommand)
    time.sleep(1)
    process.kill()

Dies ist das Skript:

#!/bin/bash
echo "sleeping five"
sleep 5
echo "slept five"

Output

$ time python poc.py 
process: sleeping five

real    0m5.053s
user    0m0.044s
sys 0m0.000s
War es hilfreich?

Lösung

ich glaube, das Problem ist, dass process.kill () nur tötet den sofortigen Kind-Prozess (bash), nicht die Teilprozesse des Bash-Skript.

Das Problem und die Lösung werden hier beschrieben:

Mit Popen (..., preexec_fn = os.setsid) eine Prozessgruppe und os.pgkill zu erstellen, um die gesamte Prozessgruppe zu töten. zB

import os
import signal
import subprocess
import time
from threading import Thread

process = None

def executeCommand(command, runCommand):
    Thread(target=runCommand, args=(command,)).start()

def runCommand(command):
    global process
    args = command.strip().split()
    process = subprocess.Popen(
        args, shell=False, stdout=subprocess.PIPE, preexec_fn=os.setsid)

    for line in process.communicate():
        if line:
            print "process:", line,

if __name__ == '__main__':
    executeCommand("./ascript.sh", runCommand)
    time.sleep(1)
    os.killpg(process.pid, signal.SIGKILL)

$ time python poc.py 
process: sleeping five

real    0m1.051s
user    0m0.032s
sys 0m0.020s

Andere Tipps

Es scheint mir, dass der einfachste Weg, dies zu tun und die Multithreading-Probleme zu umgehen wäre einen Kill-Flag aus dem Haupt-Thread zu setzen, und prüfen, ob es im Skript-laufenden Thread kurz vor der Kommunikation, zu töten das Skript, wenn das Flag True.

Es sieht aus wie Sie ein Opfer von Python Supergrobkörnige Parallelität sein können. Ändern Sie Ihr Skript folgt aus:

#!/bin/bash
echo "sleeping five"
sleep 5
echo "sleeping five again"
sleep 5
echo "slept five"

Und dann wird das Ausgangssignal:

process: sleeping five

real    0m5.134s
user    0m0.000s
sys     0m0.010s

Wenn das gesamte Skript ausgeführt, würde die Zeit 10s sein. So sieht es aus wie die Python Steuer Thread eigentlich erst ausgeführt werden, nachdem der Bash-Skript schläft. Und falls Sie Ihren Skript dies ändern:

#!/bin/bash
echo "sleeping five"
sleep 1
sleep 1
sleep 1
sleep 1
sleep 1
echo "slept five"

Dann ist der Ausgang wird:

process: sleeping five

real    0m1.150s
user    0m0.010s
sys     0m0.020s

Kurz gesagt, funktioniert der Code als logisch implementiert. :)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top