Hallo.
Ich habe einen QThread, indem ich eine Telnet-Klasse basierend auf einem QTcpSocket benutze. Der Thread besteht abgesehen von der Initialisierung der Telnet-Klasse, verschiedenen connect()-Aufrufen nur aus einer run() Methode welche auch nur ein exec() aufruft.
Das Problem ist nun, dass ich bei aktivem Thread eine merkliche CPU-Last bekomme (von 3% steigt es auf 97% laut top). Im Thread wird im wesentlichen nur auf das readyRead()-Signal des QTcpSockets gewartet und dann mittels ReadAll() gelesen und an ein QTextEdit im GUI-Thread unten angefügt.
Womit bekomme ich raus, wo die Rechenzeit verloren geht? Also ob bei der Kommunikation zw. den Threads, bei der Darstellung oder ob der Telnet-Thread vielleicht schuld ist? Was sind da die Standard-Programme und -Vorgehensweisen?
E*
QThread verbraucht zuviel CPU-Zeit. Was kann ich tun?
-
Methedrine
- Beiträge: 7
- Registriert: 15. April 2006 13:19
- Kontaktdaten:
Hallo. Danke für Deine Antwort. Eigentlich dachte ich ja, dass die textuelle Beschreibung reicht. Denn es ist wirklich nicht viel mehr drin. Aber Du hast schon recht, ich hätte sicher auch zuerst nach dem Quelltext gefragt... Also habe ich einfach mal die relevanten Klassen angehängt. Das MainWindow ist der Ausgangspunkt. Die Klasse hab' ich als einzige etwas zusammengekürzt, da da jede Menge Actions und Dialoge drin sind, die nix mit dem Problem zu tun haben.
MainWindow:
In MainWindow::worldConnect() wird ein ViewPlayer Objekt zu einem QTabWidget hinzugefügt und dessen Thread gestartet. In worldDisconnect() wird die Verbindung des Threads wieder getrennt.
Telnet:
Das ist eine Nachprogrammierung der kommerziellen Telnet-Klasse von Trolltech. Wobei ich da noch nicht ganz fertig bin. Letztlich ist hier nur ein QTcpSocket drin, welches passend verbunden wurde. Interessant ist hier nur die Telnet::readFromSocket() Methode und da auch nur die ersten 2 Zeilen. Danach ist eine Suche nach Telnet Negotiations im empfangenen Text, aber 1. ist das nicht derart rechenintensiv und 2. wird das nur interessant, wenn auch Text empfangen wurde und die Rechenzeit steigt allgemein mit dem Start des Threads an.
ConnectionThread:
Jeder Thread legt einzig eine Telnet-Instanz an und verbindet zu einem Server. Der Thread initialisiert nur das Telnet-Objekt und kümmert sich um die Weiterleitung der Daten zur richtigen Ansicht. Mehr im Moment nicht.
MultiLineEdit:
Ein Eingabefeld für Text, der zum Server geschickt werden soll. Erhält eigentlich nur die Keyboard-Events des MainWindows und schickt bei Return die Zeile los.
View:
Ein View ist eine Ansicht, die im MainWindow in Tabs verwaltet wird. Das hier ist die Basisklasse. Ist eigentlich unnötig da rein zu sehen, da dort nur Spezialisierungen sind, damit man Tab-Inhalte als DockWindows ablösen kann. Die eigentlichen Infos stehen in ViewPlayer.
ViewPlayer:
Stellt nur die Kommunikation zwischen Telnet-Klasse und dem Server in einem QTextEdit dar.
Ich freue mich über jede Idee, woran es liegen könnte, insbesondere suche ich eine Möglichkeit, die Stelle rauszufinden, an der es hakt. Vielleicht habe ich bei der Thread-Nutzung irgendwas vergessen. In einem sehr alten (Qt2) Quelltext hatte ich separate QSocketNotifier zusammen mit LowLevel Socket IO verwendet gehabt. Da traten solche Probleme nicht auf. Aber damals hatte ich auch noch keine extra Threads drin und ich denke schon, dass die QTcpSockets der Qt-Weg sind, Verbindungen zu benutzen. Ich hoffe mal, die pollen da nicht irgendwo ...
Danke schonmal im voraus an alle, die sich an der Fehlersuche versuchen.
Viele Grüße,
E*
MainWindow:
In MainWindow::worldConnect() wird ein ViewPlayer Objekt zu einem QTabWidget hinzugefügt und dessen Thread gestartet. In worldDisconnect() wird die Verbindung des Threads wieder getrennt.
Telnet:
Das ist eine Nachprogrammierung der kommerziellen Telnet-Klasse von Trolltech. Wobei ich da noch nicht ganz fertig bin. Letztlich ist hier nur ein QTcpSocket drin, welches passend verbunden wurde. Interessant ist hier nur die Telnet::readFromSocket() Methode und da auch nur die ersten 2 Zeilen. Danach ist eine Suche nach Telnet Negotiations im empfangenen Text, aber 1. ist das nicht derart rechenintensiv und 2. wird das nur interessant, wenn auch Text empfangen wurde und die Rechenzeit steigt allgemein mit dem Start des Threads an.
ConnectionThread:
Jeder Thread legt einzig eine Telnet-Instanz an und verbindet zu einem Server. Der Thread initialisiert nur das Telnet-Objekt und kümmert sich um die Weiterleitung der Daten zur richtigen Ansicht. Mehr im Moment nicht.
MultiLineEdit:
Ein Eingabefeld für Text, der zum Server geschickt werden soll. Erhält eigentlich nur die Keyboard-Events des MainWindows und schickt bei Return die Zeile los.
View:
Ein View ist eine Ansicht, die im MainWindow in Tabs verwaltet wird. Das hier ist die Basisklasse. Ist eigentlich unnötig da rein zu sehen, da dort nur Spezialisierungen sind, damit man Tab-Inhalte als DockWindows ablösen kann. Die eigentlichen Infos stehen in ViewPlayer.
ViewPlayer:
Stellt nur die Kommunikation zwischen Telnet-Klasse und dem Server in einem QTextEdit dar.
Ich freue mich über jede Idee, woran es liegen könnte, insbesondere suche ich eine Möglichkeit, die Stelle rauszufinden, an der es hakt. Vielleicht habe ich bei der Thread-Nutzung irgendwas vergessen. In einem sehr alten (Qt2) Quelltext hatte ich separate QSocketNotifier zusammen mit LowLevel Socket IO verwendet gehabt. Da traten solche Probleme nicht auf. Aber damals hatte ich auch noch keine extra Threads drin und ich denke schon, dass die QTcpSockets der Qt-Weg sind, Verbindungen zu benutzen. Ich hoffe mal, die pollen da nicht irgendwo ...
Danke schonmal im voraus an alle, die sich an der Fehlersuche versuchen.
Viele Grüße,
E*
- Dateianhänge
-
- thread-problem.zip
- Aktualisiert am 14.06.2006
- (22.1 KiB) 218-mal heruntergeladen
Zuletzt geändert von Eltharion am 14. Juni 2006 21:01, insgesamt 1-mal geändert.
So. Hab' mal wieder einen Abend lang experimentell programmiert und dabei ein paar Bugs entfernt. Zum einen habe ich festgestellt, dass ein start() Aufruf für den Thread gar nicht nötig war und selbst die run()-Methode mit dem exec()-Aufruf gelöscht werden konnte, ohne dass die Funktionalität sich veränderte. Das machte mich erstmal stutzig.
Dann habe ich mal testweise den Konstruktor-Code des Threads (der das Telnet-Objekt anlegt und connect() aufruft) in die run()-Methode verlagert und da verhielt sich schonmal einiges anders. Neben vielen Fehlermeldungen kamen ein paar Hinweise, dass erst jetzt das Telnet wirklich im Thread war und auch dort ausgeführt wurde. Man sollte also nicht aus einer perfekt funktionierenden Anwendung auf einen funktionierenden Thread schliessen. Der lief wohl nur im Leerlauf nebenher. Jedenfalls hatte ich keine Signale (started, terminated) bekommen und jetzt klappt es. Noch etwas Code zum Synchronisieren des Zugriffs von aussen (um connectHost() von ausserhalb aufzurufen) und nun scheint der Thread erstmalig wirklich zu funktionieren.
Das hat das Problem aber nicht gelöst. Die CPU-Auslastung steigt immer noch von fast 0% auf fast 100%. Interessanterweise hilft auch das Beenden der EventLoop und das Löschen des Threads nicht, den Originalzustand wieder herzustellen.
E*
Dann habe ich mal testweise den Konstruktor-Code des Threads (der das Telnet-Objekt anlegt und connect() aufruft) in die run()-Methode verlagert und da verhielt sich schonmal einiges anders. Neben vielen Fehlermeldungen kamen ein paar Hinweise, dass erst jetzt das Telnet wirklich im Thread war und auch dort ausgeführt wurde. Man sollte also nicht aus einer perfekt funktionierenden Anwendung auf einen funktionierenden Thread schliessen. Der lief wohl nur im Leerlauf nebenher. Jedenfalls hatte ich keine Signale (started, terminated) bekommen und jetzt klappt es. Noch etwas Code zum Synchronisieren des Zugriffs von aussen (um connectHost() von ausserhalb aufzurufen) und nun scheint der Thread erstmalig wirklich zu funktionieren.
Das hat das Problem aber nicht gelöst. Die CPU-Auslastung steigt immer noch von fast 0% auf fast 100%. Interessanterweise hilft auch das Beenden der EventLoop und das Löschen des Threads nicht, den Originalzustand wieder herzustellen.
E*
Zuletzt geändert von Eltharion am 14. Juni 2006 21:05, insgesamt 1-mal geändert.
-
BartSimpson
- Beiträge: 1379
- Registriert: 6. November 2004 12:03
- Kontaktdaten:
Danke erstmal für Deinen Hinweis. Ich bin zwar froh, dass ich den Custom Event losgeworden bin und jetzt endlich alles via connect() funktioniert, aber wenn es wirklich schneller wird ... Naja, ich werd's mal ausprobieren.
Ich habe heute abend nochmal herumprobiert und konnte den CPU-Last-Anstieg zu meinem QTextEdit zurückverfolgen. Warum das passiert weiss ich noch nicht, aber einfach nur ein solches Widget anlegen und was Reingetipptes darstellen (ganz wenig reicht) scheint ziemlich rechenintensiv zu sein
E*
Ich habe heute abend nochmal herumprobiert und konnte den CPU-Last-Anstieg zu meinem QTextEdit zurückverfolgen. Warum das passiert weiss ich noch nicht, aber einfach nur ein solches Widget anlegen und was Reingetipptes darstellen (ganz wenig reicht) scheint ziemlich rechenintensiv zu sein
E*