Wie starte ich einen Hintergrundprozess in Python?

Lesezeit: 10 Minuten

Benutzer-Avatar
Artem

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.

  • 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 Antwort subprocess.Popen(). Prost 🙂

    – oho

    26. Juni 2015 um 8:10 Uhr


  • @olibre Eigentlich sollte die Antwort lauten subprocess.Popen("<command>") mit -Datei, die von einem geeigneten Shebang geführt wird. Funktioniert perfekt für mich (Debian) mit Bash- und Python-Skripten, implizit shells 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

Benutzer-Avatar
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

Benutzer-Avatar
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önnen subprocess?

    – 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

Benutzer-Avatar
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

Benutzer-Avatar
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

Benutzer-Avatar
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

Benutzer-Avatar
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

1095750cookie-checkWie starte ich einen Hintergrundprozess in Python?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy