Seitdem fork() dupliziert den Speicherplatz des übergeordneten Prozesses. Wenn der übergeordnete Prozess groß ist, kann dies vermutlich zu Fehlern bei der Speicherzuweisung führen – selbst wenn der untergeordnete Prozess nicht den gesamten Speicher benötigt.
Um dieses Problem zu beheben, habe ich recherchiert, wie man externe Befehle ausführt ohne den gesamten Speicher des übergeordneten Prozesses zu duplizieren und gleichzeitig die Ausgabe des Befehls zu erfassen. Ich habe mir zwei alternative Methoden ausgedacht, die dieselbe run_command-Funktionssignatur verwenden und für einen konsistenten Vergleich genau dieselbe main-Funktion verwenden.
Methode 1: Verwendung von Multiprocessing mit „spawn“
Code: Select all
import multiprocessing
def _internal_run_command(cmd):
import subprocess
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True)
output, _ = process.communicate()
return output
def run_command(cmd):
multiprocessing.set_start_method("spawn", force=True)
with multiprocessing.Pool(1) as pool:
result = pool.apply(_internal_run_command, (cmd,))
return result
Code: Select all
import os
def run_command(cmd):
r, w = os.pipe()
try:
pid = os.posix_spawnp(
cmd[0], # File to execute
cmd, # argv
os.environ.copy(), # env
file_actions=[
(os.POSIX_SPAWN_DUP2, w, 1), # Redirect stdout to write end of pipe
(os.POSIX_SPAWN_CLOSE, r), # Close read end in child
],
)
os.close(w) # Close write end in parent
output = b""
while True:
chunk = os.read(r, 1024)
if not chunk:
break
output += chunk
os.close(r)
os.waitpid(pid, 0)
return output.decode()
except Exception as e:
print(e)
Code: Select all
if __name__ == "__main__":
output = run_command(["ls", "-l"])
print(output)
Aspekt
Methode 1: Multiprocessing mit „spawn“
Methode 2: Verwenden os.posix_spawnp()
Plattformübergreifende Kompatibilität
Ja (funktioniert unter Linux, macOS, Windows)
Nein (nur POSIX: Linux, macOS)
Implementierungskomplexität
Verwendet High-Level-Module (
Code: Select all
multiprocessing
Erfordert manuelle Verwaltung von Pipes und Dateideskriptoren
Leistung
Overhead beim Starten eines neuen Python-Interpreters
Effiziente direkte Ausführung ohne zusätzlichen Overhead
< /tr>
Meine Bedenken:
Dies ist ein ziemlich einfacher Infrastrukturcode, der manuell implementiert wird und zu unerwarteten Problemen führen kann. Ich befürchte, dass wir durch die manuelle Handhabung von Prozessen, Pipes und Dateideskriptoren das Rad für ein Problem neu erfinden, das scheinbar nicht die Ersten ist, mit denen wir konfrontiert sind.
Meine Fragen:
- Gibt es eine bessere Möglichkeit, externe Befehle von einem speicherintensiven Gerät aus auszuführen? Python-Prozess unter Linux, der fork() vermeidet und es mir ermöglicht, das zu erfassen Ausgabe?
- Gibt es beispielsweise eine Möglichkeit, subprocess oder ein anderes Standardbibliotheksmodul zu verwenden, das nicht auf fork angewiesen ist ()?
- Gibt es noch andere Vor- und Nachteile, die ich berücksichtigen sollte? diese beiden Methoden?
- Wenn es keine besseren Alternativen gibt, Ich würde gerne mehr über die damit verbundenen Kompromisse erfahren.
- Wir laufen derzeit auf Linux-Systemen, daher sind reine POSIX-Lösungen akzeptabel.
- Das Hauptziel besteht darin, Fehler bei der Speicherzuordnung zu vermeiden, die durch fork() verursacht werden, das den großen Speicherplatz des verdoppelt übergeordneter Prozess.
- Das Erfassen der Ausgabe des externen Befehls ist für die Funktionalität unserer Anwendung von wesentlicher Bedeutung.
Ich habe versucht herauszufinden, ob es gegen Regeln verstößt, indem ich Metafragen gelesen habe, war mir aber nicht sicher, also füge ich diesen Abschnitt explizit hinzu.
- Ich habe ChatGPT zum Generieren der Alternativen verwendet (habe sie aber vor dem Posten getestet und beides Alternativen).
- Ich habe ChatGPT verwendet, um die Frage zu formalisieren, aber nach vielen Iterationen der Ergebnisse sind alle Details präzise.