Umleiten von stdout und stderr um eine PyQt4 QTextEdit von einem sekundären thread aus
Stack-überlauf. Noch einmal, ich komme zu Euch in einer Zeit der not, taumelt unsicher auf den Rand des Wahnsinn. Diese Frage kann sich aus dem Titel - ist ein Zusammenschluss von mehreren anderen Fragen, die ich gesehen habe, hier beantwortet.
Ich habe eine PyQt-Anwendung, und ich möchte zu re-route, die die stdout-und stderr-Datenströme zu einem QTextEdit, das in meiner GUI ohne Verzögerung.
Anfangs fand ich folgenden stack-überlauf-Antwort: https://stackoverflow.com/a/17145093/629404
Das funktioniert perfekt, aber mit einer Einschränkung: Wenn stdout oder stderr aktualisiert werden mehrmals während der CPU-Verarbeitung ist eine relativ längere Methode, alle updates zeigen gleichzeitig, wenn der main-thread zurück zu der Anwendung, die Schleife. Leider habe ich ein paar Methoden, die bis zu 20 Sekunden dauern, um abzuschließen (Netzwerk-bezogen), und so die Anwendung nicht mehr reagiert - und das QTextEdit nicht aktualisieren, bis Sie fertig sind.
Um dieses problem zu beheben, ich alle Delegierten der GUI Bearbeitung an der Haupt-thread, und ich habe Laichzeit aus einem zweiten thread zu behandeln, die mehr Vernetzung, Operationen, Verwendung von pyqtSignals zu informieren und den Haupt-thread, wenn die Arbeit fertig ist und übergeben Sie zurück Ergebnisse. Sofort als ich begann die Prüfung der code so geschrieben, das python-interpreter begann, Absturz ohne Vorwarnung.
Dies ist, wo es wird sehr frusterating: Python hängt da - mit die Klasse von der mitgelieferten link oben - ich zugeteilt habe die sys.stdout/err-streams auf das QTextEdit-widget; PyQt widgets kann nicht geändert werden, von jedem anderen thread dann die application-thread, und seit den updates auf stdout und stderr werden, die von den sekundären worker-thread, den ich erstellt habe, verstoßen Sie gegen diese Regel. Habe ich auskommentiert, den Abschnitt des Codes, wo ich umleiten des Ausgabe-streams, und sicher genug, das Programm läuft ohne Fehler.
Das bringt mich wieder auf Platz eins, und lässt mich in einer verwirrenden situation, Vorausgesetzt, dass ich weiterhin zu behandeln GUI-bezogene Operationen in der main-thread und beschäftigen sich mit der Berechnung und mehr Operationen in einem sekundären thread (was ich verstehe, ist der beste Weg, um die Anwendung zu blockieren, wenn der Benutzer Ereignisse auslöst), wie kann ich das umleiten von Stdout und Stderr von beiden threads zu den QTextEdit-widget? Die Klasse im link oben funktioniert gut für den Haupt-thread, aber tötet python - aus dem Grund, oben beschrieben, wenn updates kommen von den zweiten thread.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Erstens, +1 für die Realisierung, wie der thread-unsicher viele der Beispiele auf stack overflow sind!
Die Lösung ist die Verwendung eines thread-safe Objekt (wie eine Python
Queue.Queue
) zu vermitteln und die übertragung von Informationen. Ich habe anbei einige Beispiel-code unten, die leitetstdout
um ein Python -Queue
. DieseQueue
gelesen von einemQThread
, strahlt Sie den Inhalt der Haupt-thread über Qt ' s signal/slot-Mechanismus (emittierenden Signale ist thread-safe). Der Haupt-thread und schreibt dann den text zu einem text Bearbeiten.Hoffe, das ist klar, fühlen Sie sich frei, Fragen zu stellen, wenn es nicht ist!
EDIT: Beachten Sie, dass die code-Beispiel nicht bereinigen QThreads nett, so erhalten Sie Warnungen gedruckt, wenn Sie zu beenden. Ich werde es verlassen, um Sie zu erweitern, um Ihren Fall prüfen und reinigen, bis der thread(s)
WriteStream
direkt das senden von Ereignissen an den Haupt-thread. In der Theorie können SieQApplication.postEvent()
post ein frisch gebaut event zu einemQObject
Ihrer macht, welche sich in den MainThread, die Aktualisierung der textbox. LeiderQApplication.postEvent
verliert Speicher in PySide (bugreports.qt-project.org/browse/PYSIDE-205), so habe ich lieber einen intermediate-thread, so dass es kompatibel bleibt mit PySide-code. Ich denke, es ist auch einfacher zu Folgen, was Los ist in meinem geposteten Beispiel.Lock()
(zum Beispiel Bibliotheken, die ich verwenden, wie diese sind h5py, zeromq, pandas), aber offensichtlich nicht alle Bibliotheken können sich aus thread-sicher mit locks (aka Qt kann nicht). Sie wirklich haben, um es zu behandeln, die auf einer Fall-zu-Fall-basis und bitten die Benutzer/Entwickler-Bibliotheken.self.queue.get()
Blöcke, wie könnte der thread beendet werden, quit?get()
nennen (dierun
- Methode) für ein bestimmtes Objekt oder einen string, und break aus der while-Schleife entsprechend. Als die queue ist thread-sicher, man könnte statt der Objekt/string/whatever in der queue aus dem Haupt-thread beenden.