Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 3145 – Asynchrones E/A für subprocess.Popen

Autor:
Eric Pruitt, Charles R. McCreary, Josiah Carlson
Status:
Zurückgezogen
Typ:
Standards Track
Erstellt:
04. Aug. 2009
Python-Version:
3.2
Post-History:


Inhaltsverzeichnis

Zusammenfassung

In seiner jetzigen Form ist die Implementierung von subprocess.Popen anfällig für Deadlocks und Blockierungen des übergeordneten Python-Skripts, während auf Daten vom Kindprozess gewartet wird. Dieses PEP schlägt vor, subprocess.Popen asynchroner zu gestalten, um diese Probleme zu mildern.

PEP Verschiebung

Eine weitere Untersuchung der in diesem PEP behandelten Konzepte wurde mindestens bis zur Klärung von PEP 3156 zurückgestellt.

Rücknahme eines PEP

Dies kann im Bug-Tracker behandelt werden. Ein spezifischer Vorschlag ist an [11] angehängt.

Motivation

Eine Suche nach „python asynchronous subprocess“ wird zahlreiche Berichte von Leuten ergeben, die einen Kindprozess ausführen und von Zeit zu Zeit mit ihm kommunizieren möchten, indem sie nur die verfügbaren Daten lesen, anstatt zu blockieren und auf die Erzeugung von Daten durch das Programm zu warten [1] [2] [3]. Das aktuelle Verhalten des subprocess-Moduls ist, dass Deadlocks häufig vorkommen und dokumentiert sind, wenn ein Benutzer Daten über die Datei-Objekte stdin, stderr und stdout sendet oder empfängt [4] [5]. Während `communicate` verwendet werden kann, um einige Pufferungsprobleme zu mildern, wird der Elternprozess immer noch blockieren, wenn er versucht, Daten zu lesen, und es sind keine Daten vom Kindprozess verfügbar.

Begründung

Es gibt einen dokumentierten Bedarf an asynchroner, nicht-blockierender Funktionalität in subprocess.Popen [6] [7] [2] [3]. Die Einbeziehung des Codes würde den Nutzen der Python-Standardbibliothek verbessern, die auf Unix- und Windows-Builds von Python verwendet werden kann. Praktisch jedes E/A-Objekt in Python hat eine dateiähnliche Hülle irgendeiner Art. Sockets fungieren bereits so, und für Strings gibt es StringIO. Popen kann durch einfache Verwendung der Methoden, die an den dateiähnlichen Objekten subprocess.Popen.stderr, stdout und stdin angehängt sind, wie eine Datei behandelt werden. Wenn jedoch die `read`- und `write`-Methoden dieser Optionen verwendet werden, hat man nicht den Vorteil einer asynchronen E/A. Im vorgeschlagenen Lösung wickelt die Hülle die asynchronen Methoden ab, um ein Datei-Objekt nachzuahmen.

Referenzimplementierung

Ich pflege ein Google Code-Repository, das alle meine Änderungen einschließlich Tests und Dokumentation enthält [9], sowie einen Blog, der die Probleme detailliert beschreibt, auf die ich während der Entwicklung gestoßen bin [10].

Ich habe daran gearbeitet, nicht-blockierende asynchrone E/A im subprocess-Modul zu implementieren, sowie eine Wrapper-Klasse für subprocess.Popen, die es einem ausgeführten Prozess ermöglicht, eine Datei zu ersetzen, indem alle Methoden und Attribute von Datei-Objekten dupliziert werden.

Zwei Basisfunktionen wurden der subprocess.Popen-Klasse hinzugefügt: Popen.send und Popen._recv, jeweils mit zwei separaten Implementierungen, eine für Windows und eine für Unix-basierte Systeme. Die Windows-Implementierung verwendet ctypes, um auf die Funktionen der Kernel 32 DLL zuzugreifen, die zur Steuerung von Pipes auf asynchrone Weise benötigt werden. Auf Unix-basierten Systemen dient die Python-Schnittstelle für die Dateisteuerung demselben Zweck. Die verschiedenen Implementierungen von Popen.send und Popen._recv haben identische Argumente, damit Code, der diese Funktionen verwendet, plattformübergreifend funktioniert.

Beim Aufruf der Funktion Popen._recv wird der Pipe-Name als Argument übergeben. Daher gibt es die Funktion Popen.recv, die `stdout` standardmäßig als Pipe für Popen._recv auswählt. Popen.recv_err wählt `stderr` standardmäßig als Pipe aus. Popen.recv und Popen.recv_err sind viel einfacher zu lesen und zu verstehen als Popen._recv('stdout' ...) und Popen._recv('stderr' ...).

Da die Funktion Popen._recv nicht auf die Erzeugung von Daten wartet, bevor sie einen Wert zurückgibt, kann sie leere Bytes zurückgeben. Popen.asyncread behandelt dieses Problem, indem es alle über ein bestimmtes Zeitintervall gelesenen Daten zurückgibt.

Die Klasse ProcessIOWrapper verwendet die Funktionen asyncread und asyncwrite, um einem Prozess zu ermöglichen, sich wie eine Datei zu verhalten, sodass keine blockierenden Probleme auftreten, die bei der Verwendung der von einem subprocess.Popen-Aufruf erzeugten `stdout`- und `stdin`-Datei-Objekte entstehen können.

Referenzen

[8] subprocess.rst - subprocdev - Project Hosting on Google Code https://web.archive.org/web/20130306074135/http://code.google.com/p/subprocdev/source/browse/doc/subprocess.rst?spec=svn2c925e935cad0166d5da85e37c742d8e7f609de5&r=2c925e935cad0166d5da85e37c742d8e7f609de5


Quelle: https://github.com/python/peps/blob/main/peps/pep-3145.rst

Zuletzt geändert: 2025-02-01 08:55:40 GMT