Ich versuche, ein Shell-Skript auf die viel besser lesbare Python-Version zu portieren. Das Original-Shell-Skript startet mehrere Prozesse (Dienstprogramme, Monitore usw.) im Hintergrund mit “&”. Wie kann ich den gleichen Effekt in Python erzielen? Ich möchte, dass diese Prozesse nicht sterben, wenn die Python-Skripte abgeschlossen sind. Ich bin mir sicher, dass es irgendwie mit dem Konzept eines Daemons zusammenhängt, aber ich konnte nicht finden, wie man das einfach macht.
Wie starte ich einen Hintergrundprozess in Python?
Artem
Dan
Während die Lösung von jkp funktioniert, ist die neuere Art, Dinge zu tun (und die Art und Weise, wie die Dokumentation es empfiehlt), die zu verwenden subprocess
Modul. Für einfache Befehle ist es das Äquivalent, aber es bietet mehr Optionen, wenn Sie etwas Kompliziertes tun möchten.
Beispiel für Ihren Fall:
import subprocess
subprocess.Popen(["rm","-r","some.file"])
Das wird laufen rm -r some.file
im Hintergrund. Beachten Sie das Aufrufen .communicate()
auf dem Objekt zurückgegeben von Popen
wird blockieren, bis es abgeschlossen ist, also tun Sie das nicht, wenn Sie möchten, dass es im Hintergrund läuft:
import subprocess
ls_output=subprocess.Popen(["sleep", "30"])
ls_output.communicate() # Will block for 30 seconds
Siehe Dokumentation hier.
Auch ein Punkt zur Klarstellung: “Hintergrund”, wie Sie ihn hier verwenden, ist ein reines Shell-Konzept; Technisch gesehen meinen Sie, dass Sie einen Prozess starten möchten, ohne ihn zu blockieren, während Sie darauf warten, dass er abgeschlossen wird. Ich habe hier jedoch “Hintergrund” verwendet, um auf Shell-Hintergrund-ähnliches Verhalten zu verweisen.
-
@Dan: Wie beende ich den Prozess, wenn er im Hintergrund läuft? Ich möchte es eine Weile ausführen (es ist ein Daemon, mit dem ich interagiere) und es beenden, wenn ich damit fertig bin. Die Unterlagen sind nicht hilfreich…
– Juan
7. Juli 2014 um 5:36 Uhr
-
@Dan, aber muss ich dafür nicht die PID kennen? Aktivitätsmonitor/Task-Manager ist keine Option (muss programmgesteuert geschehen).
– Juan
12. Juli 2014 um 16:56 Uhr
-
ok, wie zwingen Sie den Prozess in den Hintergrund, wenn Sie das Ergebnis von Popen () benötigen, um in seine stdin zu schreiben?
– Michael
19. Juli 2014 um 20:23 Uhr
-
@JFSebastian: Ich habe es interpretiert als “wie kann ich einen unabhängigen Prozess erstellen, der die Ausführung des aktuellen Programms nicht stoppt”. Wie würden Sie vorschlagen, dass ich es bearbeite, um dies deutlicher zu machen?
– Dan
17. Dezember 2014 um 4:51 Uhr
-
@Dan
proc = subprocess.Popen(["rm","-r","some.file"])
dann töten:proc.terminate()
– BEI
9. Juni 2015 um 4:52 Uhr
jkp
Notiz: Diese Antwort ist weniger aktuell als zum Zeitpunkt der Veröffentlichung im Jahr 2009. Mit dem subprocess
Das in anderen Antworten gezeigte Modul wird jetzt empfohlen in den Dokumenten
(Beachten Sie, dass das subprocess-Modul leistungsfähigere Möglichkeiten zum Erzeugen neuer Prozesse und zum Abrufen ihrer Ergebnisse bietet; die Verwendung dieses Moduls ist der Verwendung dieser Funktionen vorzuziehen.)
Wenn Sie möchten, dass Ihr Prozess im Hintergrund startet, können Sie entweder verwenden system()
und rufen Sie es auf die gleiche Weise auf, wie es Ihr Shell-Skript getan hat, oder Sie können es spawn
es:
import os
os.spawnl(os.P_DETACH, 'some_long_running_command')
(Alternativ können Sie auch die weniger tragbare Version ausprobieren os.P_NOWAIT
Flagge).
Siehe die Dokumentation hier.
-
Hinweis: Sie müssen den vollständigen Pfad zur ausführbaren Datei angeben. Diese Funktion verwendet die PATH-Variable nicht und die Variante, die sie verwendet, ist unter Windows nicht verfügbar.
– sorin
28. Oktober 2009 um 17:14 Uhr
-
Straight Up stürzt Python für mich ab.
– Pablo
28. Februar 2011 um 13:58 Uhr
-
os.P_DETACH wurde durch os.P_NOWAIT ersetzt.
– man selbst
6. Juli 2012 um 19:28 Uhr
-
Könnten die Leute vorschlagen, zu verwenden
subprocess
Geben Sie uns einen Hinweis, wie Sie einen Prozess mit trennen könnensubprocess
?– rakslice
11. Februar 2014 um 21:56 Uhr
-
Wie kann ich ein Python-Skript (z. B. „attach.py“) verwenden, um einen Hintergrundprozess zu finden und dessen E/A umzuleiten, sodass „attach.py“ im Hintergrund von „some_long_running_prog“ lesen/schreiben kann?
– raof01
5. März 2014 um 6:46 Uhr
Eli Gerichtsschreiber
Sie möchten wahrscheinlich die Antwort auf “Wie man einen externen Befehl in Python aufruft”.
Der einfachste Ansatz ist die Verwendung von os.system
Funktion, zB:
import os
os.system("some_command &")
Im Grunde alles, was Sie an die weitergeben system
Die Funktion wird genauso ausgeführt, als ob Sie sie in einem Skript an die Shell übergeben hätten.
-
IMHO, Python-Skripte werden normalerweise plattformübergreifend geschrieben, und wenn es eine einfache plattformübergreifende Lösung gibt, ist es besser, dabei zu bleiben. Nie wissen, ob Sie in Zukunft mit einer anderen Plattform arbeiten müssen 🙂 Oder ob ein anderer Mann Ihr Skript auf seine Plattform migrieren möchte.
– d9k
1. Mai 2016 um 2:37 Uhr
-
Dieser Befehl ist synchron (dh er wartet immer auf eine Beendigung des gestarteten Prozesses).
– tav
7. Oktober 2017 um 9:10 Uhr
-
@d9k ist os.system nicht portabel?
– klarer_Träumer
4. Juni 2018 um 17:55 Uhr
-
@d9k positioniert Sie die Wahl, etwas im Hintergrund auszuführen, nicht bereits im Posix-Land? Was würdest du unter Windows machen? Als Dienst ausführen?
– klarer_Träumer
4. Juni 2018 um 17:57 Uhr
-
Wie kann ich dies verwenden, wenn ich einen Befehl aus einem bestimmten Ordner ausführen muss?
– mrRobot
16. November 2019 um 16:14 Uhr
fp
Ich habe das hier gefunden:
Unter Windows (Win XP) wird der übergeordnete Prozess erst beendet, wenn die longtask.py
hat seine Arbeit beendet. Es ist nicht das, was Sie in CGI-Skript wollen. Das Problem ist nicht spezifisch für Python, in der PHP-Community sind die Probleme dieselben.
Die Lösung ist zu bestehen DETACHED_PROCESS
Prozesserstellungs-Flag zum Basiswert CreateProcess
Funktion in der Win-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
Jimmy KD
Verwenden subprocess.Popen()
mit dem close_fds=True
-Parameter, der es ermöglicht, dass der erzeugte Unterprozess vom Python-Prozess selbst getrennt wird und auch nach dem Beenden von Python weiter ausgeführt wird.
https://gist.github.com/yinjimmy/d6ad0742d03d54518e9f
import os, time, sys, subprocess
if len(sys.argv) == 2:
time.sleep(5)
print 'track end'
if sys.platform == 'darwin':
subprocess.Popen(['say', 'hello'])
else:
print 'main begin'
subprocess.Popen(['python', os.path.realpath(__file__), '0'], close_fds=True)
print 'main end'
-
In Windows löst es sich nicht, aber die Verwendung des Parameters creationflags funktioniert
– Smart Manoj
26. April 2018 um 15:43 Uhr
-
Diese Lösung hinterlässt einen Unterprozess als Zombie unter Linux.
– TitanFighter
3. April 2019 um 14:24 Uhr
-
@TitanFighter dies kann vermieden werden, indem SIGCHLD SIG_IGN gesetzt wird: stackoverflow.com/questions/16807603/…
– Segelfisch009
30. Mai 2020 um 5:20 Uhr
-
danke @Jimmy, deine Antwort ist die EINZIGE Lösung, die für mich funktioniert.
– Segelfisch009
30. Mai 2020 um 5:23 Uhr
-
Das
close_fds=True
Option funktioniert durch Trennen des Prozesses, kehrte aber nicht zu meinem Python-Programm zurück. In der Hoffnung, eine Option zu finden, die einen Prozess wirklich ausführt und in den Hintergrund schickt und dann zum Python-Programm zurückkehrt.– Nav
27. April 2021 um 7:27 Uhr
Beide erfassen die Ausgabe und laufen im Hintergrund mit threading
Wie auf dieser Antwort erwähnt, wenn Sie die Ausgabe mit erfassen stdout=
und dann versuchen read()
dann blockiert der Prozess.
Es gibt jedoch Fälle, in denen Sie dies benötigen. Zum Beispiel wollte ich starten zwei Prozesse, die über einen Port miteinander kommunizierenund speichern Sie ihre stdout in einer Protokolldatei und stdout.
Das threading
Modul ermöglicht uns das.
Sehen Sie sich zunächst an, wie Sie den Teil der Ausgabeumleitung allein in dieser Frage ausführen: Python Popen: Gleichzeitig in die stdout-UND Protokolldatei schreiben
Dann:
main.py
#!/usr/bin/env python3
import os
import subprocess
import sys
import threading
def output_reader(proc, file):
while True:
byte = proc.stdout.read(1)
if byte:
sys.stdout.buffer.write(byte)
sys.stdout.flush()
file.buffer.write(byte)
else:
break
with subprocess.Popen(['./sleep.py', '0'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc1, \
subprocess.Popen(['./sleep.py', '10'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc2, \
open('log1.log', 'w') as file1, \
open('log2.log', 'w') as file2:
t1 = threading.Thread(target=output_reader, args=(proc1, file1))
t2 = threading.Thread(target=output_reader, args=(proc2, file2))
t1.start()
t2.start()
t1.join()
t2.join()
schlafen.py
#!/usr/bin/env python3
import sys
import time
for i in range(4):
print(i + int(sys.argv[1]))
sys.stdout.flush()
time.sleep(0.5)
Nach dem Rennen:
./main.py
stdout wird alle 0,5 Sekunden aktualisiert, damit alle zwei Zeilen Folgendes enthalten:
0
10
1
11
2
12
3
13
und jede Protokolldatei enthält das entsprechende Protokoll für einen bestimmten Prozess.
Inspiriert von: https://eli.thegreenplace.net/2017/interacting-with-a-long-running-child-process-in-python/
Getestet auf Ubuntu 18.04, Python 3.6.7.
-
In Windows löst es sich nicht, aber die Verwendung des Parameters creationflags funktioniert
– Smart Manoj
26. April 2018 um 15:43 Uhr
-
Diese Lösung hinterlässt einen Unterprozess als Zombie unter Linux.
– TitanFighter
3. April 2019 um 14:24 Uhr
-
@TitanFighter dies kann vermieden werden, indem SIGCHLD SIG_IGN gesetzt wird: stackoverflow.com/questions/16807603/…
– Segelfisch009
30. Mai 2020 um 5:20 Uhr
-
danke @Jimmy, deine Antwort ist die EINZIGE Lösung, die für mich funktioniert.
– Segelfisch009
30. Mai 2020 um 5:23 Uhr
-
Das
close_fds=True
Option funktioniert durch Trennen des Prozesses, kehrte aber nicht zu meinem Python-Programm zurück. In der Hoffnung, eine Option zu finden, die einen Prozess wirklich ausführt und in den Hintergrund schickt und dann zum Python-Programm zurückkehrt.– Nav
27. April 2021 um 7:27 Uhr
Gerald Senarclens de Grancy
Wahrscheinlich möchten Sie damit beginnen, das os-Modul zu untersuchen, um verschiedene Threads zu forken (indem Sie eine interaktive Sitzung öffnen und help(os) ausgeben). Die relevanten Funktionen sind Fork und alle Exec-Funktionen. Um Ihnen eine Vorstellung davon zu geben, wie Sie anfangen sollen, fügen Sie so etwas in eine Funktion ein, die den Fork ausführt (die Funktion muss eine Liste oder ein Tupel ‘args’ als Argument annehmen, das den Namen des Programms und seine Parameter enthält; Sie können auch wollen um stdin, out und err für den neuen Thread zu definieren):
try:
pid = os.fork()
except OSError, e:
## some debug output
sys.exit(1)
if pid == 0:
## eventually use os.putenv(..) to set environment variables
## os.execv strips of args[0] for the arguments
os.execv(args[0], args)
-
os.fork()
ist wirklich nützlich, hat aber den bemerkenswerten Nachteil, dass es nur auf * nix verfügbar ist.– Evan Fosmark
28. Juli 2009 um 19:15 Uhr
-
Das einzige Problem mit os.fork ist, dass es win32-spezifisch ist.
– jkp
28. Juli 2009 um 19:15 Uhr
-
Weitere Details zu diesem Ansatz: Erstellen eines Daemons auf Python-Art
– Amir Ali Akbari
20. April 2014 um 2:47 Uhr
-
Ähnliche Effekte können Sie auch mit erreichen
threading
: stackoverflow.com/a/53751896/895245 Ich denke, das könnte unter Windows funktionieren.– Ciro Santilli Путлер Капут 六四事
12. Dezember 2018 um 21:53 Uhr
Die wirklich doppelte Frage ist, wie man ein externes Skript im Hintergrund startet und ausführt?. Prost 😉
– oho
13. November 2013 um 9:30 Uhr
Hallo Artem. Bitte akzeptieren Sie Dans Antwort, weil (1) mehr Stimmen, (2)
subprocess.Popen()
ist der neue empfohlene Weg seit 2010 (wir sind jetzt im Jahr 2015) und (3) die doppelte Frage, die hier umleitet, hat auch eine akzeptierte Antwortsubprocess.Popen()
. Prost 🙂– oho
26. Juni 2015 um 8:10 Uhr
@olibre Eigentlich sollte die Antwort lauten-Datei, die von einem geeigneten Shebang geführt wird. Funktioniert perfekt für mich (Debian) mit Bash- und Python-Skripten, implizit
subprocess.Popen("<command>")
mitshell
s und überlebt seinen übergeordneten Prozess.stdout
geht zum selben Terminal wie das der Eltern. Das funktioniert also ähnlich&
in einer Shell, die OPs Anfrage war. Aber zum Teufel, alle Fragen sind sehr komplex, während ein wenig Testen es in kürzester Zeit zeigte 😉– Flachbier
26. Juni 2015 um 18:54 Uhr
Für Hintergrundinformationen siehe vielleicht auch stackoverflow.com/a/51950538/874188
– Dreier
18. September 2018 um 5:40 Uhr