Einige Hinweise zum Trennen des Kindprozesses vom aufrufenden Prozess (Starten des Kindprozesses im Hintergrund).
Angenommen, Sie wollen eine lange Aufgabe von einem CGI-Skript aus starten. Das heißt, der untergeordnete Prozess sollte länger laufen als der CGI-Skript-Ausführungsprozess.
Das klassische Beispiel aus der Dokumentation des Subprozessmoduls lautet:
import subprocess
import sys
# Some code here
pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess
# Some more code here
Die Idee dahinter ist, dass man in der Zeile "call subprocess" nicht warten will, bis longtask.py fertig ist. Aber es ist nicht klar, was nach der Zeile "some more code here" aus dem Beispiel passiert.
Meine Zielplattform war FreeBSD, aber die Entwicklung fand unter Windows statt, also habe ich das Problem zuerst unter Windows gelöst.
Unter Windows (Windows XP) wird der übergeordnete Prozess nicht beendet, bevor longtask.py seine Arbeit beendet hat. Das ist nicht das, was Sie in einem CGI-Skript wollen. Das Problem ist nicht spezifisch für Python; in der PHP-Gemeinschaft sind die Probleme die gleichen.
Die Lösung ist die Übergabe von DETACHED_PROCESS Flagge für Prozesserstellung auf die zugrunde liegende CreateProcess-Funktion in der Windows-API. Wenn Sie pywin32 installiert haben, können Sie das Flag aus dem win32process-Modul importieren, ansonsten sollten Sie es selbst definieren:
DETACHED_PROCESS = 0x00000008
pid = subprocess.Popen([sys.executable, "longtask.py"],
creationflags=DETACHED_PROCESS).pid
/* UPD 2015.10.27 @eryksun merkt in einem Kommentar unten an, dass das semantisch korrekte Flag CREATE_NEW_CONSOLE (0x00000010) ist */
Unter FreeBSD gibt es ein weiteres Problem: Wenn der Elternprozess beendet ist, beendet er auch die Kindprozesse. Und das ist auch nicht das, was man in einem CGI-Skript will. Einige Experimente zeigten, dass das Problem in der gemeinsamen Nutzung von sys.stdout zu liegen schien. Und die funktionierende Lösung war die folgende:
pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
Ich habe den Code nicht auf anderen Plattformen überprüft und kenne die Gründe für das Verhalten unter FreeBSD nicht. Wenn jemand etwas weiß, bitte ich um einen Hinweis. Googeln über das Starten von Hintergrundprozessen in Python hat bisher nichts ergeben.
0 Stimmen
Ich verstehe das nicht, was ist falsch an
import os; os.system('pip list | grep anatome')
? Zumindest kann man damit Piping machen, wie mein Beispiel zeigt. Es ist nicht klar, wie man das mitimport subprocess; subprocess.run(["ls", "-l"])
.