400 Stimmen

Wie startet man einen Hintergrundprozess in Python?

Ich versuche, ein Shell-Skript auf die viel besser lesbare Python-Version zu portieren. Das ursprüngliche Shell-Skript startet mehrere Prozesse (Dienstprogramme, Monitore, etc.) im Hintergrund mit "&". Wie kann ich den gleichen Effekt in Python erreichen? Ich möchte, dass diese Prozesse nicht absterben, wenn die Python-Skripte beendet sind. Ich bin mir sicher, dass es irgendwie mit dem Konzept eines Daemons zusammenhängt, aber ich konnte nicht herausfinden, wie man das einfach machen kann.

16voto

Beide erfassen die Ausgabe und laufen im Hintergrund mit threading

Wie erwähnt zu dieser Antwort wenn Sie die Ausgabe mit stdout= und versuchen dann read() dann wird der Prozess blockiert.

Es gibt jedoch Fälle, in denen Sie dies benötigen. Ich wollte zum Beispiel zwei Prozesse, die über einen Port miteinander kommunizieren und speichern ihr stdout in einer Protokolldatei und stdout.

Die threading Modul erlaubt uns das zu tun.

Schauen Sie sich zunächst an, wie Sie den Teil der Ausgabeumleitung in dieser Frage allein durchführen können: Python Popen: Gleichzeitig nach stdout UND in die 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()

schlaf.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 Laufen:

./main.py

stdout wird alle 0,5 Sekunden für jeweils zwei Zeilen aktualisiert:

0
10
1
11
2
12
3
13

und jede Protokolldatei enthält das jeweilige Protokoll für einen bestimmten Prozess.

Inspiriert durch: https://eli.thegreenplace.net/2017/interacting-with-a-long-running-child-process-in-python/

Getestet auf Ubuntu 18.04, Python 3.6.7.

13voto

Wahrscheinlich möchten Sie zunächst das os-Modul zum Forken verschiedener Threads untersuchen (indem Sie eine interaktive Sitzung öffnen und help(os) aufrufen). Die relevanten Funktionen sind fork und eine der exec-Funktionen. Um Ihnen eine Idee zu geben, wie Sie beginnen können, fügen Sie etwas wie das Folgende in eine Funktion ein, die das Forking durchführt (die Funktion muss eine Liste oder ein Tupel 'args' als Argument nehmen, das den Namen des Programms und seine Parameter enthält; Sie möchten vielleicht auch stdin, out und err für den neuen Thread 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)

1voto

Sie können verwenden

import os
pid = os.fork()
if pid == 0:
    Continue to other code ...

Dadurch wird der Python-Prozess im Hintergrund ausgeführt.

0voto

Ich habe das noch nicht ausprobiert, aber die Verwendung von .pyw-Dateien anstelle von .py-Dateien sollte helfen. pyw-Dateien haben keine Konsole, so dass sie theoretisch nicht erscheinen und wie ein Hintergrundprozess arbeiten sollten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X