Wenn Sie Code in einem Prozess sicher ausführen, leiten Sie stdout in multithreading.Process um

8

Ich arbeite an einem Datensatz von einem MOOC. Ich habe eine Menge von python3-Code-Schnipsel, die ich ausführen muss und die Ergebnisse von erhalten. Um dies zu tun, habe ich ein Python-Skript geschrieben, das jedes Snippet durchläuft. Für jedes Snippet I:

  1. Erzeuge neue StringIO Objekte
  2. Setze sys.stdout und sys.stderr auf meine stringIO Puffer
  3. Führen Sie das Code-Snippet in einem threading.thread -Objekt
  4. aus
  5. Verknüpfen Sie den Thread
  6. Protokollieren Sie die Ergebnisse in den StringIO-Puffern
  7. Wiederherstellen von stdout und stderr

Das funktioniert gut für "richtigen" Code, aber das hat in anderen Fällen Probleme:

  • Wenn der Code eine Endlosschleife hat, wird thread.join den Thread nicht beenden. Der Thread ist ein Daemon-Thread, also läuft er ruhig im Hintergrund, bis meine Schleife beendet ist.
  • Wenn der Code eine Endlosschleife mit einem print() hat, beginnt der Thread, mein tatsächliches stdout zu überschreiben, wenn ich es auf den Standardwert zurücksetze (weg vom StringIO-Puffer). Dies belastet meine Berichterstattung.

Hier ist mein aktueller Code:

%Vor%

Um diesen Fall zu behandeln, habe ich versucht, multithreading.Process und / oder contextlib.redirect_stdout zu verwenden, um den Code in einem Prozess auszuführen (dann kann ich process.terminate() aufrufen), aber ich habe keine Erfolgserfassung stdout / stderr.

Meine Frage ist also: Wie kann ich stdout / stderr von einem Prozess umleiten oder aufzeichnen? Oder gibt es eine andere Möglichkeit, die Ausgabe von beliebigem Code auszuführen und zu erfassen?

(Und ja, ich weiß, dass das im Allgemeinen eine schlechte Idee ist; ich benutze es in einer virtuellen Maschine, nur für den Fall, dass sich irgendwo Schadcode befindet)

Python-Version ist 3.5.3

Aktualisieren

Mir fällt auf, dass es in dieser Situation etwas mehr Flexibilität gibt. Ich habe eine Funktion, preprocess(code) , die einen Code als String akzeptiert und ändert. Meistens habe ich es benutzt, um den Wert einiger Variablen mit regulären Ausdrücken auszutauschen.

Hier ist eine Beispielimplementierung:

%Vor%

Ich könnte die Vorverarbeitungsfunktion verwenden, um STDOUT

umzuleiten     
Zack 13.11.2017, 01:26
quelle

2 Antworten

3

Die Kommunikation mit dem laufenden Prozess ist in Python nicht einfach. Aus irgendeinem Grund können Sie dies nur einmal im Subprozesslebenszyklus tun. Aus meiner Erfahrung ist es am besten, einen Thread zu starten, der einen Prozess startet und nach Timeout seine Ausgabe erhält und den Subprozess beendet.

Etwas wie:

%Vor%

So, führen Sie einen Thread-Scharfrichter, der subprocess_with_timeout aufruft. Es sollte die Eingaben verarbeiten und die Ergebnisse speichern.

Eine andere Idee ist die Verwendung eines Webservers für die IPC. Siehe diesen Link

    
igrinis 20.11.2017, 10:45
quelle
0

Was ist mit subprocess.check_output ? Sie könnten python -c {snippet} damit aufrufen, oder wenn es länger ist, schreiben Sie das Snippet in eine temporäre .py -Datei. check_output (und alle anderen Funktionen in subprocess ) haben einen timeout -Parameter.

Die allgemeine Idee ist dann:

%Vor%

Beispiel läuft in IPython:

%Vor%

Beachten Sie, dass check_output eine bytes Sequenz zurückgibt, also müssen Sie sie in str umwandeln. Oder Sie können den Parameter encoding von check_output verwenden.

    
David Nemeskey 20.11.2017 09:22
quelle