it-swarm.com.de

Wie starte ich einen Hintergrundprozess in Python?

Ich versuche, ein Shell-Skript auf die viel besser lesbare Version python=) zu portieren. Das ursprüngliche 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 abbrechen, wenn die Skripte für python abgeschlossen sind. Ich bin sicher, dass dies irgendwie mit dem Konzept eines Daemons zusammenhängt, aber ich konnte nicht es ist nicht leicht zu finden, wie man das macht.

247
Artem

Hinweis : Diese Antwort ist weniger aktuell als im Jahr 2009. Es wird jetzt empfohlen, das in anderen Antworten gezeigte subprocess -Modul zu verwenden. in den Dokumenten

(Beachten Sie, dass das Unterprozessmodul leistungsfähigere Funktionen zum Starten neuer Prozesse und 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 system() verwenden und auf die gleiche Weise aufrufen, wie es Ihr Shell-Skript getan hat, oder Sie können spawn ausführen:

import os
os.spawnl(os.P_DETACH, 'some_long_running_command')

(Alternativ können Sie auch das weniger tragbare os.P_NOWAIT Flagge).

Siehe Dokumentation hier .

72
jkp

Während die Lösung von jkp funktioniert, besteht die neuere Vorgehensweise (und die in der Dokumentation empfohlene Vorgehensweise) in der Verwendung des Moduls subprocess. Für einfache Befehle ist es ä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"])

Dies sollte rm -r somefile Im Hintergrund ausführen. Aber seien Sie vorsichtig: subprocess.Popen() führt nur dann einen Prozess im Hintergrund aus, wenn nichts im python script von der Ausgabe des Befehls being abhängt run:

Beispielsweise wird der folgende Befehl nicht im Hintergrund ausgeführt:

import subprocess
ls_output=subprocess.Popen(["ls", "-a"], stdout=subprocess.PIPE)

Siehe die Dokumentation hier .

Auch ein Punkt der Klarstellung: "Hintergrund" rein ein Shell-Konzept: Was Sie wahrscheinlich wollen, ist, einen neuen Prozess zu erzeugen. Ich habe hier "Hintergrund" verwendet, um auf ein Shell-Hintergrund-ähnliches Verhalten zu verweisen, verwechsle dies jedoch nicht mit dem Vorgang, der sich tatsächlich im Hintergrund befindet.

331
Dan

Sie möchten wahrscheinlich die Antwort auf "So rufen Sie einen externen Befehl in Python auf" .

Der einfachste Ansatz ist die Verwendung von os.system Funktion, z.B.

import os
os.system("some_command &")

Grundsätzlich wird alles, was Sie an die Funktion system übergeben, genauso ausgeführt, als ob Sie es in einem Skript an die Shell übergeben hätten.

39
Eli Courtwright

Ich fand das hier :

Unter Windows (Win XP) wird der übergeordnete Prozess erst beendet, wenn longtask.py hat seine Arbeit beendet. Es ist nicht das, was Sie in CGI-Skripten wollen. Das Problem ist nicht spezifisch für Python, in der PHP Community sind die Probleme gleich.

Die Lösung besteht darin, DETACHED_PROCESSProcess Creation Flag zur zugrunde liegenden Funktion CreateProcess in der Win-API. Wenn Sie pywin32 installiert haben, können Sie das Flag aus dem win32process-Modul importieren, andernfalls sollten Sie es selbst definieren:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid
28
f p

Verwenden Sie subprocess.Popen() mit dem close_fds=True Parameter, mit dem der erzeugte Unterprozess vom Python Prozess selbst getrennt und auch nach dem Beenden von Python weiter ausgeführt werden kann.

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'
20
Jimmy Yin

Sie möchten wahrscheinlich das Modul os untersuchen, um verschiedene Threads zu forken (indem Sie eine interaktive Sitzung öffnen und help (os) ausgeben). Die relevanten Funktionen sind Fork und alle ausführbaren. Um Ihnen eine Vorstellung davon zu geben, wie Sie beginnen sollen, fügen Sie so etwas in eine Funktion ein, die die Verzweigung ausführt (die Funktion muss eine Liste oder Tupel 'args' als Argument verwenden, das den Namen des Programms und seine Parameter enthält; möglicherweise möchten Sie dies auch So definieren Sie stdin, out und err für den neuen Thread:

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)

Sowohl Ausgabe erfassen als auch im Hintergrund mit threading ausführen

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

Es gibt jedoch Fälle, in denen Sie dies benötigen. Zum Beispiel wollte ich zwei Prozesse, die über einen Port zwischen ihnen kommunizieren starten und ihre Standardausgabe in einer Protokolldatei und einer Standardausgabe speichern.

Das threading Modul erlaubt uns das zu tun.

Schauen Sie sich zunächst an, wie Sie den Teil der Ausgabeumleitung allein in dieser Frage durchführen: Python Popen: Schreiben Sie gleichzeitig in die Datei stdout AND log

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()

sleep.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 sind:

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 unter Ubuntu 18.04, Python 3.6.7.