Subprozesse¶
Quellcode: Lib/asyncio/subprocess.py, Lib/asyncio/base_subprocess.py
Dieser Abschnitt beschreibt High-Level-APIs mit async/await für asyncio, um Subprozesse zu erstellen und zu verwalten.
Hier ist ein Beispiel dafür, wie asyncio einen Shell-Befehl ausführen und sein Ergebnis abrufen kann
import asyncio
async def run(cmd):
proc = await asyncio.create_subprocess_shell(
cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
print(f'[{cmd!r} exited with {proc.returncode}]')
if stdout:
print(f'[stdout]\n{stdout.decode()}')
if stderr:
print(f'[stderr]\n{stderr.decode()}')
asyncio.run(run('ls /zzz'))
wird ausgeben
['ls /zzz' exited with 1]
[stderr]
ls: /zzz: No such file or directory
Da alle Subprozessfunktionen von asyncio asynchron sind und asyncio viele Werkzeuge für die Arbeit mit solchen Funktionen bietet, ist es einfach, mehrere Subprozesse parallel auszuführen und zu überwachen. Es ist tatsächlich trivial, das obige Beispiel so zu modifizieren, dass mehrere Befehle gleichzeitig ausgeführt werden
async def main():
await asyncio.gather(
run('ls /zzz'),
run('sleep 1; echo "hello"'))
asyncio.run(main())
Siehe auch die Untersektion Beispiele.
Subprozesse erstellen¶
- async asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶
Erstellt einen Subprozess.
Das Argument limit legt das Pufferlimit für
StreamReader-Wrapper fürstdoutundstderrfest (wennsubprocess.PIPEan die Argumente stdout und stderr übergeben wird).Gibt eine
Process-Instanz zurück.Weitere Parameter finden Sie in der Dokumentation von
loop.subprocess_exec().Geändert in Version 3.10: Das Argument loop wurde entfernt.
- async asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶
Führt den Shell-Befehl cmd aus.
Das Argument limit legt das Pufferlimit für
StreamReader-Wrapper fürstdoutundstderrfest (wennsubprocess.PIPEan die Argumente stdout und stderr übergeben wird).Gibt eine
Process-Instanz zurück.Weitere Parameter finden Sie in der Dokumentation von
loop.subprocess_shell().Wichtig
Es liegt in der Verantwortung der Anwendung sicherzustellen, dass alle Leerzeichen und Sonderzeichen ordnungsgemäß maskiert werden, um Shell-Injection-Schwachstellen zu vermeiden. Die Funktion
shlex.quote()kann verwendet werden, um Leerzeichen und spezielle Shell-Zeichen in Zeichenfolgen, die zur Konstruktion von Shell-Befehlen verwendet werden, ordnungsgemäß zu maskieren.Geändert in Version 3.10: Das Argument loop wurde entfernt.
Hinweis
Subprozesse sind unter Windows verfügbar, wenn eine ProactorEventLoop verwendet wird. Details finden Sie unter Subprocess Support unter Windows.
Siehe auch
asyncio bietet auch die folgenden Low-Level-APIs für die Arbeit mit Subprozessen: loop.subprocess_exec(), loop.subprocess_shell(), loop.connect_read_pipe(), loop.connect_write_pipe() sowie die Subprocess Transports und Subprocess Protocols.
Konstanten¶
- asyncio.subprocess.PIPE¶
Kann an die Argumente stdin, stdout oder stderr übergeben werden.
Wenn PIPE an das Argument stdin übergeben wird, zeigt das Attribut
Process.stdinauf eineStreamWriter-Instanz.Wenn PIPE an die Argumente stdout oder stderr übergeben wird, zeigen die Attribute
Process.stdoutundProcess.stderraufStreamReader-Instanzen.
- asyncio.subprocess.STDOUT¶
Spezieller Wert, der als Argument stderr verwendet werden kann und angibt, dass der Standardfehler in die Standardausgabe umgeleitet werden soll.
- asyncio.subprocess.DEVNULL¶
Spezieller Wert, der als Argument stdin, stdout oder stderr für Funktionen zur Prozessverwaltung verwendet werden kann. Er gibt an, dass die spezielle Datei
os.devnullfür den entsprechenden Subprozessstream verwendet wird.
Interaktion mit Subprozessen¶
Sowohl die Funktionen create_subprocess_exec() als auch create_subprocess_shell() geben Instanzen der Process-Klasse zurück. Process ist ein High-Level-Wrapper, der die Kommunikation mit Subprozessen und die Überwachung ihres Abschlusses ermöglicht.
- class asyncio.subprocess.Process¶
Ein Objekt, das OS-Prozesse umschließt, die von den Funktionen
create_subprocess_exec()undcreate_subprocess_shell()erstellt wurden.Diese Klasse ist so konzipiert, dass sie eine ähnliche API wie die Klasse
subprocess.Popenaufweist, es gibt jedoch einige bemerkenswerte Unterschiedeim Gegensatz zu Popen haben Process-Instanzen keine Entsprechung zur Methode
poll();die Methoden
communicate()undwait()haben keinen Parameter timeout: verwenden Sie stattdessen die Funktionwait_for();die Methode
Process.wait()ist asynchron, während die Methodesubprocess.Popen.wait()als blockierende Busy-Loop implementiert ist;der Parameter universal_newlines wird nicht unterstützt.
Diese Klasse ist nicht threadsicher.
Siehe auch den Abschnitt Subprozesse und Threads.
- async wait()¶
Wartet auf die Beendigung des Kindprozesses.
Setzt und gibt das Attribut
returncode.Hinweis
Diese Methode kann zu einem Deadlock führen, wenn
stdout=PIPEoderstderr=PIPEverwendet wird und der Kindprozess so viele Ausgaben erzeugt, dass er darauf wartet, dass der OS-Pipe-Puffer mehr Daten aufnehmen kann. Verwenden Sie die Methodecommunicate(), wenn Pipes verwendet werden, um diese Bedingung zu vermeiden.
- async communicate(input=None)¶
Interaktion mit dem Prozess
sendet Daten an stdin (wenn input nicht
Noneist);schließt stdin;
liest Daten von stdout und stderr, bis EOF erreicht ist;
wartet auf die Beendigung des Prozesses.
Das optionale Argument input sind die Daten (
bytes-Objekt), die an den Kindprozess gesendet werden.Gibt ein Tupel
(stdout_data, stderr_data)zurück.Wenn beim Schreiben von input in stdin eine Ausnahme
BrokenPipeErroroderConnectionResetErrorausgelöst wird, wird die Ausnahme ignoriert. Diese Bedingung tritt auf, wenn der Prozess beendet wird, bevor alle Daten in stdin geschrieben wurden.Wenn Daten an stdin des Prozesses gesendet werden sollen, muss der Prozess mit
stdin=PIPEerstellt werden. Wenn etwas anderes alsNoneim Ergebnis-Tupel gewünscht wird, muss der Prozess mit den Argumentenstdout=PIPEund/oderstderr=PIPEerstellt werden.Beachten Sie, dass die gelesenen Daten im Speicher gepuffert werden. Verwenden Sie diese Methode daher nicht, wenn die Datengröße groß oder unbegrenzt ist.
Geändert in Version 3.12: stdin wird auch geschlossen, wenn
input=Noneist.
- send_signal(signal)¶
Sendet das Signal signal an den Kindprozess.
Hinweis
Unter Windows ist
SIGTERMein Alias fürterminate().CTRL_C_EVENTundCTRL_BREAK_EVENTkönnen an Prozesse gesendet werden, die mit einem creationflags-Parameter gestartet wurden, derCREATE_NEW_PROCESS_GROUPenthält.
- terminate()¶
Beendet den Kindprozess.
Auf POSIX-Systemen sendet diese Methode
SIGTERMan den Kindprozess.Unter Windows wird die Win32 API-Funktion
TerminateProcess()aufgerufen, um den Kindprozess zu beenden.
- kill()¶
Beendet den Kindprozess.
Auf POSIX-Systemen sendet diese Methode
SIGKILLan den Kindprozess.Unter Windows ist diese Methode ein Alias für
terminate().
- stdin¶
Standard-Eingabestream (
StreamWriter) oderNone, wenn der Prozess mitstdin=Noneerstellt wurde.
- stdout¶
Standard-Ausgabestream (
StreamReader) oderNone, wenn der Prozess mitstdout=Noneerstellt wurde.
- stderr¶
Standard-Fehlerstrom (
StreamReader) oderNone, wenn der Prozess mitstderr=Noneerstellt wurde.
Warnung
Verwenden Sie die Methode
communicate()anstelle vonprocess.stdin.write(),await process.stdout.read()oderawait process.stderr.read(). Dies vermeidet Deadlocks, da Streams das Lesen oder Schreiben pausieren und den Kindprozess blockieren.- pid¶
Prozessidentifikationsnummer (PID).
Beachten Sie, dass für Prozesse, die von der Funktion
create_subprocess_shell()erstellt wurden, dieses Attribut die PID der gestarteten Shell ist.
- returncode¶
Rückgabecode des Prozesses nach seiner Beendigung.
Ein Wert von
Nonezeigt an, dass der Prozess noch nicht beendet wurde.Ein negativer Wert
-Nzeigt an, dass das Kind durch das SignalNbeendet wurde (nur POSIX).
Subprozesse und Threads¶
Die Standard-Event-Loop von asyncio unterstützt standardmäßig die Ausführung von Subprozessen aus verschiedenen Threads.
Unter Windows werden Subprozesse ausschließlich von ProactorEventLoop (Standard) bereitgestellt. SelectorEventLoop unterstützt keine Subprozesse.
Beachten Sie, dass alternative Implementierungen von Event-Loops eigene Einschränkungen haben können; siehe deren Dokumentation.
Siehe auch
Der Abschnitt Concurrency und Multithreading in asyncio.
Beispiele¶
Ein Beispiel, das die Klasse Process zur Steuerung eines Subprozesses und die Klasse StreamReader zum Lesen aus dessen Standardausgabe verwendet.
Der Subprozess wird von der Funktion create_subprocess_exec() erstellt
import asyncio
import sys
async def get_date():
code = 'import datetime; print(datetime.datetime.now())'
# Create the subprocess; redirect the standard output
# into a pipe.
proc = await asyncio.create_subprocess_exec(
sys.executable, '-c', code,
stdout=asyncio.subprocess.PIPE)
# Read one line of output.
data = await proc.stdout.readline()
line = data.decode('ascii').rstrip()
# Wait for the subprocess exit.
await proc.wait()
return line
date = asyncio.run(get_date())
print(f"Current date: {date}")
Siehe auch das gleiche Beispiel, das mit Low-Level-APIs geschrieben wurde.