Python-multiprocessing: Wie kann ich ZUVERLÄSSIG umleiten von stdout von einem Kind-Prozess?
NB. Ich habe gesehen, Log-Ausgabe von multiprocessing.Prozess - leider, es gibt keine Antwort auf diese Frage.
Erstelle ich ein child-Prozess (unter windows) über multiprocessing. Ich will alle des child-Prozesses auf stdout-und stderr-Ausgabe umgeleitet zu werden in einer log-Datei, sondern erscheinen auf der Konsole. Der einzige Vorschlag, den ich gesehen habe, ist für das Kind Prozess sys.stdout in eine Datei. Dies gilt jedoch nicht effektiv umleiten stdout Ausgabe, aufgrund des Verhaltens des stdout-Umleitung auf Windows.
Um das problem zu veranschaulichen, erstellen Sie eine Windows-DLL mit dem folgenden code
#include <iostream>
extern "C"
{
__declspec(dllexport) void writeToStdOut()
{
std::cout << "Writing to STDOUT from test DLL" << std::endl;
}
}
Dann erstellen und ausführen eines python-Skript wie das folgende, welches die Einfuhren dieser DLL ein und ruft die Funktion:
from ctypes import *
import sys
print
print "Writing to STDOUT from python, before redirect"
print
sys.stdout = open("stdout_redirect_log.txt", "w")
print "Writing to STDOUT from python, after redirect"
testdll = CDLL("Release/stdout_test.dll")
testdll.writeToStdOut()
Um zu sehen, die das gleiche Verhalten wie mir, es ist wahrscheinlich notwendig für die DLL gebaut werden, gegen eine andere C-Laufzeit als das man Python verwendet. In meinem Fall, python erstellt mit Visual Studio 2010, aber meine DLL ist gebaut mit VS 2005.
Dem Verhalten, das ich sehe, ist, dass die Konsole zeigt:
> stdout_test.py
Writing to STDOUT from python, before redirect
Writing to STDOUT from test DLL
Während die Datei stdout_redirect_log.txt endet mit:
Writing to STDOUT from python, after redirect
In anderen Worten, die Einstellung sys.stdout ist fehlgeschlagen Umleitung des stdout-Ausgabe generiert, die von der DLL. Dies ist nicht verwunderlich angesichts der Art der zugrunde liegenden APIs für stdout-Umleitung in Windows. Ich habe auf dieses problem in der Muttersprache/C++ - Ebene vor und nie einen Weg gefunden, um zuverlässig umleiten von stdout in einem Prozess. Es wurde extern erstellt werden.
Dies ist eigentlich der Grund, ich bin der Einführung eine untergeordnete Prozess - es ist so, dass ich eine Verbindung herstellen können, das von außen auf den Rohren und gewährleisten damit, dass ich bin abfangen aller seiner Ausgabe. Ich kann auf jeden Fall dazu starten Sie den Prozess manuell mit pywin32, aber ich würde sehr gerne in der Lage sein, die Einrichtungen des multiprocessing, insbesondere die Möglichkeit der Kommunikation mit dem Kind-Prozess über eine multiprocessing-Pipe-Objekt, um den Projektfortschritt zu informieren. Die Frage ist, ob es irgendeinen Weg gibt, um beide verwenden multiprocessing für seine IPC-Einrichtungen und zuverlässig umleiten des Kindes stdout und stderr Ausgabe in eine Datei.
UPDATE: Sie sich den Quellcode für multiprocessing.Prozesse, es ist ein statisches Element, _Popen, die aussieht wie es verwendet werden kann, um das überschreiben der Klasse verwendet zum erstellen des Prozesses. Wenn es auf None gesetzt ist (default), verwendet es eine multiprocessing."forking"._Popen, aber es sieht so aus, indem er sagte
multiprocessing.Process._Popen = MyPopenClass
Könnte ich überschreiben der Prozess der Schöpfung. Jedoch, obwohl, ich könnte ableiten dies von multiprocessing."forking"._Popen, wie es aussieht, würde ich die Kopie einer Reihe von internen Sachen in meiner Implementierung, das klingt flockig und nicht sehr zukunftssicher. Wenn das die einzige Wahl, die ich denke, würde ich wohl zu plump das ganze manuell mit pywin32 statt.
- Können Sie mit der Win32-API zum starten des teilprozesses, oder hat es zu tun mit bestehenden Python-Bibliotheken?
- Ja, ich erwähnte in der Frage, dass "ich kann auf jeden Fall dazu starten Sie den Prozess manuell mit pywin32". Es schien nur eine Schande, aufzugeben, die auf höherer Ebene, unabhängig von der Plattform multiprocessing-Modul, weil von dem, was scheint wie eine triviale bisschen fehlende Funktionalität - die Fähigkeit zu geben stdin/stdout-handles für das Kind.
- Der Ansatz, den ich nehme (es sei denn, jemand kommt mit einer besseren alternative) ist, starten Sie den Prozess über den subprocess-Modul, mit stdin/stdout in eine Datei umgeleitet, und verwenden Sie eine native Windows-named pipe für den Fortgang der Kommunikation.
- Trifft es nicht richtig funktionieren, wenn Sie umleiten, sys.stdout des übergeordneten Prozesses, vor dem starten des Kindes?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die Lösung, die Sie vorschlagen, ist eine gute Idee: erstellen Sie Ihre Prozesse manuell, so dass du explizit den Zugang zu Ihren stdout/stderr-Datei-handles. Sie können dann erstellen Sie einen socket für die Kommunikation mit der sub-Prozess, und verwenden Sie multiprocessing.Verbindung über die Steckdose (multiprocessing.Rohr erzeugt die gleiche Art von connection-Objekt, so sollten Sie auf alle die gleiche IPC-Funktionalität).
Hier ist eine zwei-file Beispiel.
master.py:
subproc.py:
Können Sie auch sehen wollen, die erste Antwort auf diese Frage um nicht-blockierende lese aus dem Teilprozess.
Ich glaube nicht, dass Sie eine bessere option als die Umleitung einen Teilprozess in einer Datei, wie Sie erwähnt in Ihrem Kommentar.
Den Weg Konsolen stdin/out/err, arbeiten in windows ist jeder Prozess, wenn er geboren wird, hat seine std Griffe definiert. Sie können ändern Sie mit SetStdHandle. Wenn Sie das ändern-python -
sys.stdout
Sie nur ändern, wo python druckt Zeug, nicht, wo die anderen DLL ' s sind Druck-Sachen. Teil des CRT in der DLL ist mit GetStdHandle um herauszufinden, wo Sie ausgedruckt. Wenn Sie möchten, können Sie tun, was Verrohrung Sie wollen in der windows-API in der DLL oder in Ihrem python-Skript mit pywin32. Obwohl ich denke, es wird einfacher sein mit Teilprozess.Ich nehme an, ich bin off base und etwas fehlt, aber für was es Wert ist, hier ist, was kam in den Sinn, wenn ich lese Ihre Frage.
Wenn Sie abfangen kann alle stdout und stderr (ich habe diesen Eindruck aus Ihrer Frage), dann warum nicht hinzufügen oder wickeln, die capture-Funktion, um jeden Ihrer Prozesse? Dann senden Sie, was erfasst wird, über eine Warteschlange an einen Verbraucher, die das tun können, was Sie wollen, die mit allen Ausgängen?
In meiner situation, die ich geändert
sys.stdout.write
zu schreiben PySide QTextEdit. Ich konnte nicht Lesensys.stdout
und ich wusste nicht, wie zu ändernsys.stdout
lesbar sein. Ich habe zwei Rohre. Eine für die Standardausgabe und die andere für stderr. In der separaten Prozess, den ich umleitensys.stdout
undsys.stderr
auf die untergeordnete Verbindung des multiprocessing-Rohr. Auf der main-Prozess ich habe zwei threads zu Lesen, die über stdout und stderr übergeordneten Leitung und Umleitung der pipe-Daten zusys.stdout
undsys.stderr
.