Ich möchte eine performante Gui in Qt schreiben.
Und im Hintergrund sollen per Ethernet Nachrichten empfangen werden, die
dann in der Gui angezeigt werden.
Sollte ich die Empfangsfunktion in einen eigenen Thread auslagern?
Bzw. wann sollte man Funktionen in eigene Threads auslagern?
Sollen sollen sollst du gar nichts, und müssen müssen mußt du auch
nichts, aber können können könntest du das tun.
Das qt aber eigentlich alles für sich erledigt, brauchst du nur auf die
passenden Signale zu reagieren.
Oliver
Otto schrieb:> Aber wenn ich alle 10 ms eine Nachricht aus dem Ethernet Stack kommt> wird die Gui doch möglichen zu langsam!
Und was würde der Benutzer für Vorteile daraus ziehen, wenn er alle 10ms
neue Informationen gezeigt bekommt? Keine, weil er die Informationen so
schnell gar nicht erfassen kann. Also existiert dein Problem nur in
deiner Vorstellung, stimmts?
Nein, die Frage des TO ist durchaus berechtigt.
Ich habe das gleiche Problem dadurch gelöst,
dass ich die (in meinem Fall bis zu 4000 Nachrichten / s) in einem
eigenen
Thread empfange und dekodiere, sie an die GUI weiterreiche und dort
zwischenspeichere. Alle 300ms wird der Speicher (eine QList o. ä.)
ausgelesen und die GUI aktualisiert (bis zu 10000 Zeilen).
Gruß
Olaf
Olaf Dreyer schrieb:> Thread empfange und dekodiere, sie an die GUI weiterreiche und dort> zwischenspeichere. Alle 300ms wird der Speicher (eine QList o. ä.)> ausgelesen und die GUI aktualisiert (bis zu 10000 Zeilen).
Und wie soll der Benutzer 10000 Zeichen / 300 ms lesen können?
Was soll das bringen?
Ich schrieb Zeilen, nicht Zeichen.
Wenn ich z. B. ein Autoradio teste das per Ethernet seine Traceausgaben
schickt, dann kan ich schon bei der Änderung der einzelnen Testparameter
erkennen, ob das Gerät vermehrt Fehlermeldungen ausspuckt. Solche werden
natürlich an der GUI durch SyntaxHighlighting hervorgerufen.
Gruß
Olaf
Meister Eder schrieb:> Und was würde der Benutzer für Vorteile daraus ziehen, wenn er alle 10ms> neue Informationen gezeigt bekommt? Keine, weil er die Informationen so> schnell gar nicht erfassen kann. Also existiert dein Problem nur in> deiner Vorstellung, stimmts?
Hallo,
du hast recht der Benutzer kann die Inforamtion so schnell nicht
erfassen.
Aber angenommen ich ersetzt den Ethernet Stack durch einen Can-Stack.
Hierbei empfängt mein Anzeigegerät Prozessdaten mit hoher
Geschwindigkeit (alle 10 ms). Wie kann ich verhindern, dass mein Gerät
nicht ständig damit beschäftigt ist, Nachrichten zu empfangen?
Die GUI kannst bzw. solltest du nicht in einen Thread schieben. Du
kannst aber, wie bereits gesagt wurde, zeitaufwändige Aufgaben in einem
eigenen Thread machen. Aber wie immer bei Threads ist die Frage, ob das
a) tatsächlich schneller ist im Endeffekt und b) den Aufwand lohnt. Mein
Rat wäre, es zuerst ohne zu versuchen, und die Thread-Variante nur zu
probieren wenn's tatsächlich zu langsam ist.
Grüße,
Sven
Otto schrieb:> Wie kann ich verhindern, dass mein Gerät> nicht ständig damit beschäftigt ist, Nachrichten zu empfangen?
Gar nicht, und da liegt auch dein Denkfehler. Wenn die ganze verfügbare
Rechenzeit dafür drauf geht, Daten zu empfangen, dann hilft ein
zusätzlicher Thread auch nicht weiter. Mehr verfügbare Rechenzeit
bekommst du dadurch nicht. Außer natürlich, bei einem Mehrkernprozessor
liegen Kerne brach, die durch einen zusätzlichen Tthread genutzt werden
können.
Oliver
Das ist Unfug. Die GUI zu verwalten braucht nur sehr wenig Zeit, und
selbst wenn die CPU fast komplett mit dem Verarbeiten von irgendwas
beschäftigt ist, ist es kein Problem währenddessen noch einen
Fortschrittsbalken anzuzeigen oder was auch immer.
Sven B. schrieb:> Das ist Unfug. Die GUI zu verwalten braucht nur sehr wenig Zeit,> und> selbst wenn die CPU fast komplett mit dem Verarbeiten von irgendwas> beschäftigt ist, ist es kein Problem währenddessen noch einen> Fortschrittsbalken anzuzeigen oder was auch immer.
Ein Fortschrittsbalken ist kein Problem.
Allerdings soll auch navigiert und gescrollt werden können. Und das
kostet CPU Leistung.
Kommt halt drauf an, was man genau anzeigen will. Insbesondere halt
darauf achten, dass nur so oft gerendert wird wie das auch sinnvoll ist,
dass das effizient geschieht, und dass insbesondere nur auf die dazu
nötigen Daten zugegriffen wird und nicht auf alle. Es gibt genug
Anwendungen, die das ordentlich vormachen, ein typischer
Terminal-Emulator zum Beispiel kann problemlos zehntausende Zeilen Text
rendern während eine in ihm ausgeführte Anwendung die CPU quasi komplett
auslastet.
Was effizienter ist, hängt wirklich von den Details ab, aber wenn ein
Datenstrom reinkommt, kann ein Thread der dann auf dem Socket blockiert
durchaus die sinnvollste Möglichkeit sein. Man muss da halt überlegen
wie man das mit dem Rest des Programmes synchronisiert.
Aber, für Fehlermeldungen eines Gerätes braucht man eine GUI Software.
So was macht man entweder ganz einfach per TCP-Socket quasi per Telnet,
oder per UDP in einem Syslog kompatiblen Format. Dadurch wird die "GUI"
zu einem einfachen
netcat <DUT-IP> <PORT> > <Dateiname> &
tail -f <Dateiname>
Sven B. schrieb:> a) tatsächlich schneller ist im Endeffekt und b) den Aufwand lohnt.
Das Problem ist ja weniger die Ausführungsgeschwindiogkeit sondern die
Frage ob die GUI noch zügig auf Mausereignisse reagiert während im
Hintergrund noch was anderes gemacht wird. Es gibt nichts störenderes
als eine GUI die einen Klick nicht augenblicklich entgegennimmt
sondern stattdessen wie eingefroren erscheint.
Ein separater Thread is weniger Aufwand, nicht mehr. Wenn Du alles im
Main-Thread machen willst musst Du aberwitzige Verrrenkungen anstellen
um gleichzeitig noch die GUI-Eventloop am laufen zu halten, ein separate
Thread jedoch läuft einfach so für sich und kann sich voll auf das
konzentrieren wozu er da ist und auch mal 99% seiner Zeit in nem
blockierenden read() stecken ohne sich um den Rest der Anwendung
irgendwelche Gedanken machen zu müssen. Das ist wesentlich einfacher zu
handhaben.
Es kommt halt immer auf den konkreten Fall an. In dieser Allgemeinheit
lässt sich die Fragestellung nicht diskutieren. Klar, wenn du mit einer
synchronen API zu tun hast die auch mal länger braucht, führt um einen
extra-Thread wohl kein Weg herum.
Siebzehn Zu Fuenfzehn schrieb:> Ich wuerde den extra thread fuer den externen Prozess verwenden.
dito. ohne qt zu kennen finde ich daß das schnelle datenfetchen und die
gui nicht "in die selbe loop" gehören. das sind zwei unterscheidliche
dinge - die gui soll "in echtzeit" auf nutzereingaben reagieren, und der
fetcher soll genügend cpu-cycles haben um seiner aufgabe nachzukommen.
wer kennt nicht mindestens ein programm das nicht reagiert weil es beim
datenverarbeiten nicht mehr auf den gedrückten abbrechen button
reagiert…?
Es kommt halt drauf an. Wenn du eh einen externen Prozess startest und
alles was du mit dem tust ist seine Ausgabe in einem Textfeld
darzustellen dann bringt dir der extra-Thread genau gar nichts, der
macht alles nur schlechter und komplizierter. Der extra-Thread bringt in
dem Fall nur was, wenn du sehr rechenaufwendiges Post-Processing mit dem
Output von dem Prozess machst.
Sven B. schrieb:> Es kommt halt drauf an. Wenn du eh einen externen Prozess startest
Wo steht da daß er nen separaten Prozess startet? Er will
Netzwerk-Kommunikation machen und das macht man traditionell mit nem
separaten Thread, das ist sauber, übersichtlich, wesentlich einfacher zu
handhaben und ist in 3 Minuten hingeschrieben. Dazu braucht man:
* die API-Funktion um einen Thread zu starten (1 Zeile Code)
* while (!terminated) {
* den Code um vom Socket zu lesen (braucht er sowieso)
* Empfangenes Paket da hinschreiben wo es der Main Thread abholen kann
* Mit Main-Thread synchronisieren (1 Zeile)
* }
Bernd K. schrieb:> Sven B. schrieb:>> Es kommt halt drauf an. Wenn du eh einen externen Prozess startest>> Wo steht da daß er nen separaten Prozess startet? Er will> Netzwerk-Kommunikation machen und das macht man traditionell mit nem> separaten Thread,
Wusste ich garnicht. Muss da was verpasst haben.
> das ist sauber, übersichtlich, wesentlich einfacher zu> handhaben und ist in 3 Minuten hingeschrieben.
Ah ja.
> Dazu braucht man:>> * die API-Funktion um einen Thread zu starten (1 Zeile Code)> * while (!terminated) {> * den Code um vom Socket zu lesen (braucht er sowieso)> * Empfangenes Paket da hinschreiben wo es der Main Thread abholen kann> * Mit Main-Thread synchronisieren (1 Zeile)> * }
Ok, und jetzt erklärst du uns bitte noch etwas über 'volatile' und die
Synchronisation. Ich bin mir recht sicher, dass es auf einmal doch mehr
als 3 Minuten braucht, wenn man sich bemüht, keine ranzige Müllware zu
programmieren.
Und schließlich sollte man noch klären, warum überhaupt der
Datenempfang so tödlich für die GUI ist. Meistens kommt dabei nämlich
heraus, dass der Thread nur eine faule Ausrede dafür ist, dass man keine
sauberen Zustandsautomaten programmieren kann/will.
Nase schrieb:> Meistens kommt dabei nämlich> heraus, dass der Thread nur eine faule Ausrede dafür ist, dass man keine> sauberen Zustandsautomaten programmieren kann/will.
Was würde denn so ein "sauberer Zustandsautomat" prinzipiell machen ?
Otto schrieb:> Was würde denn so ein "sauberer Zustandsautomat" prinzipiell machen ?
Daten empfangen, wenn es welche zu empfangen gibt und verarbeiten, wenn
es was zu verarbeiten gibt. Der Zustandsautomat ersetzt damit die
lineare Verarbeitung, die man faul in einen Thread reinklatscht. Der
Automat dagegen blockiert nicht, sondern muss nur regelmäßig angestoßen
(aufgerufen) werden.
Wenn man nicht gerade auf einem Mehrkernsystem arbeitet, wird es nämlich
durch einen Thread nicht effizienter, weil auch der Thread keine
zusätzliche Rechenzeit herbeizaubert. Man muss sich eben Gedanken
machen, wie oft man den Automaten anstößt und wie oft (dazwischen) man
die Eventloop der GUI anstößt. Und das wird auch mit einem Thread nicht
besser.
Wenn der Thread gerade in einer atomaren Operation festhängt, dann ist
das Scheduling nämlich auch im Eimer und die GUI friert ein. Präemptives
Scheduling macht nämlich auch nichts anderes, als den Programmfluss an
einer (geeigneten) Stelle abzuwürgen und umzuschalten.
Aber was passiert, wenn ständig Daten verarbeitet werden müssen?
-> Der Nachrichtenpuffer muss ausgelesen werden, damit er nicht
überläuft.
-> Es werden alle 10 ms Nachrichten in den Puffer geschrieben.
Otto schrieb:> Aber was passiert, wenn ständig Daten verarbeitet werden müssen?> -> Der Nachrichtenpuffer muss ausgelesen werden, damit er nicht> überläuft.> -> Es werden alle 10 ms Nachrichten in den Puffer geschrieben.
Und was passiert, wenn du das mit Threads machst?
Ich weis das ich dadurch nicht mehr Rechenzeit bekommen.
Aber was soll ich sonst machen?
Den Puffer auslesen und die Hälfte aller Nachrichten gleich verwerfen?
Otto schrieb:> Ich weis das ich dadurch nicht mehr Rechenzeit bekommen.> Aber was soll ich sonst machen?> Den Puffer auslesen und die Hälfte aller Nachrichten gleich verwerfen?
Um die Frage beantworten zu können, mußt du dir nur überlegen, ob das
auslesen mehr als 10ms dauert. Wenn nicht, kannst du den Rest der Zeit
für die GUI verwenden. Muß ja nicht am Stück sein, die Zeit kann man
sich ja mittels Statemachine aufteilen. Wenn das Auslesen aber wirklich
länger als 10ms dauern sollte und die Nachrichten kommen aller 10ms
rein, dann kannst du, wie du schon gesagt hast, keine Rechenzeit
herbeizaubern.
Otto schrieb:> Ich weis das ich dadurch nicht mehr Rechenzeit bekommen.> Aber was soll ich sonst machen?> Den Puffer auslesen und die Hälfte aller Nachrichten gleich verwerfen?
Das musst du schon selbst beantworten. Aber du erkennst ja, dass es mit
einem Thread nicht besser wird. Eher schlechter wegen der
Kontextwechsel.
Wenn du mit dem Auswerten nicht hinterherkommst, kannst du die GUI
vernachlässigen um dort Rechenzeit zu sparen. Natürlich friert die dann
ein. Wenn du dann immer noch nicht hinterherkommst, dann wirst du wohl
Nachrichten verwerfen müssen.
Wenn die Auswertung aber (zeitlich) teuer ist aber die Zeit der
Erfassung nur begrenzt ist, dann könntest du die Nachrichten während der
Erfassung unbewertet in einen großen Puffer schreiben und dann
anschließend in Ruhe auswerten?
> Muß ja nicht am Stück sein, die Zeit kann man> sich ja mittels Statemachine aufteilen. Wenn das Auslesen aber wirklich> länger als 10ms dauern sollte und die Nachrichten kommen aller 10ms> rein
...
> Man muss sich eben Gedanken> machen, wie oft man den Automaten anstößt und wie oft (dazwischen) man> die Eventloop der GUI anstößt.
...
Klar, möglichst fummelig, low-level und kaum sinnvoll skalierbar.
> Eher schlechter wegen der Kontextwechsel.
Das Unterforum hier heißt PC-Programmierung, nicht uC-Programmierung.
> dann kannst du, wie du schon gesagt hast, keine Rechenzeit> herbeizaubern.
...
> wird es nämlich durch einen Thread nicht effizienter, weil auch der> Thread keine zusätzliche Rechenzeit herbeizaubert.
Bevor man Ratschläge gibt, solle man evtl. erst einmal den Unterschied
zwischen I/O-bound und CPU-bound kennen ...
Aloha schrieb:> Bevor man Ratschläge gibt, solle man evtl. erst einmal den Unterschied> zwischen I/O-bound und CPU-bound kennen ...
Hast du außer Genörgel auch noch etwas beizutragen, was den OT irgendwie
weiterbringt? Ansonsten solltest du vielleicht zuerst das ganze Thema
lesen.
Aber gottseidank - ja GOTTSEIDANK - skalieren Threads genau bei diesem
Problem hier so ausgezeichnet gut.
Geh doch bitte wieder Java-Bloat spielen.
Aloha schrieb:> Klar, möglichst fummelig, low-level und kaum sinnvoll skalierbar.
Was ist bitte an einer Statemachine "fummelig, low-level und kaum
sinnvoll skalierbar"? Das weißt bestimmt nur du allein. ;-)
Das ist nicht fummelig. In Qt benutzt du zum Beispiel QTcpSocket und
verbindest dich mit dem readyRead()-Signal. Das in einem Thread zu
machen bringt so gut wie nichts, außer du willst halt wie gesagt
rechenaufwändiges Post-Processing machen.
Sven B. schrieb:> Das ist nicht fummelig. In Qt benutzt du zum Beispiel QTcpSocket und> verbindest dich mit dem readyRead()-Signal.
Zum Beispiel, genau.
Und was hast du dann? Richtig: Einen Zustandsautomaten. Denn nichts
anderes ist das QT-Eventzeugs nämlich.
> Das in einem Thread zu> machen bringt so gut wie nichts, außer du willst halt wie gesagt> rechenaufwändiges Post-Processing machen.
Und selbst da bringt der Thread nichts, wenn keine Rechenzeit mehr da
ist oder wenn der Scheduler die beiden Threads auf dieselbe CPU packt.
Außer, dass man sich noch um die Synchronisierung kümmern muss.
Ok, QT-Signale gehen auch threadsicher, aber einfacher wirds auch nicht.
Nase schrieb:> Sven B. schrieb:>> Das ist nicht fummelig. In Qt benutzt du zum Beispiel QTcpSocket und>> verbindest dich mit dem readyRead()-Signal.> Zum Beispiel, genau.> Und was hast du dann? Richtig: Einen Zustandsautomaten. Denn nichts> anderes ist das QT-Eventzeugs nämlich.
Jo, klar, hat auch niemand was gegenteiliges behauptet :-)
Nase schrieb:> Wenn man nicht gerade auf einem Mehrkernsystem arbeitet, wird es nämlich> durch einen Thread nicht effizienter
Nochmal zum Mitschreiben: Es geht nicht darum ob es effizienter wird
denn nichts davon ist CPU-bound sondern es geht darum daß es mit einem
separaten Thread simpler, aufgeräumter, unkomplizierter, weniger Code
und einfacher wartbar wird.
Separation of concerns. Das GUI hat nicht im Netzwerk herumzufuhrwerken,
es hat 100% seiner Zeit auf die Maus und die Tastatur zu warten und ab
und zu mal Teile der Fenster neu zu malen und sonst nichts.
Ach und das hat übrigens auch nichts mit "volatile" zu tun und
Synchronize() ist bei mir eine Zeile Code (und eine Handler-Funktion auf
der anderen Seite) und wenns Asynchron laufen soll dann gibts dafür
ebenfalls simple Mechanismen, jedes Framework das ich bis jetzt gesehen
habe bringt solche Mechanismen schon mit und das Framework das OP
verwendet mit Sicherheit ebenfalls.
Bernd K. schrieb:> sondern es geht darum daß es mit einem> separaten Thread simpler, aufgeräumter, unkomplizierter, weniger Code> und einfacher wartbar wird.
Das ist meiner Meinung nach definitiv falsch. Wahrscheinlich 80% aller
Bugs haben irgendwas mit Threads zu tun, und die vermeidet man am
einfachsten, indem man keine Threads hat wenn es irgendwie geht. Mit
aufgeräumtem Code hat das überhaupt nichts zu tun (warum sollte es?).
Sven B. schrieb:> 80% aller> Bugs haben irgendwas mit Threads zu tun,
Nachweis?
> und die vermeidet man am> einfachsten, indem man keine Threads hat wenn es irgendwie geht.
Ich weiß nicht welche Probleme manche Leute mit Threads haben, es gibt
ein paar Sachen die man beachten muß, aber das muß man bei tausend
anderen Designpatterns ebenfalls, Threads per se sind auch nicht
irgendwie inherent komplizierter als alles andere. Und sie helfen
oftmals verschiedene Abläufe die vollkommen unabhängig voneinander (auch
und vor allem zeitlich) ablaufen sollen sauber voneinander zu
entkoppeln. Im Wesentlichen muss man lediglich an der einen kleinen
Stelle aufpassen an der zwei Threads miteinander Informationen
austauschen und dafür gibts klare und bewährte Vorgehensweisen. In dem
Beispiel mit einem GUI-Thread und einem Netwerk-Thread wäre das absolut
trivial.
Bernd K. schrieb:> Nachweis?
In der Anwendung in der ich da ein bisschen den Überblick habe durch was
Crashes verursacht werden ist das so.
> In dem> Beispiel mit einem GUI-Thread und einem Netwerk-Thread wäre das absolut> trivial.
Threads sind viele Dinge, aber nach meiner Erfahrung nie trivial.
Vielleicht bin ich auch einfach nur doof, aber ich finde den ganzen
Thread-Kram im Detail sehr kompliziert und sehr leicht falsch zu machen.
Sven B. schrieb:> Threads sind viele Dinge, aber nach meiner Erfahrung nie trivial.> Vielleicht bin ich auch einfach nur doof, aber ich finde den ganzen> Thread-Kram im Detail sehr kompliziert und sehr leicht falsch zu machen.
Dann benutzt du die falsche Programmiersprache ;-))
Bernd K. schrieb:> Nase schrieb:>> Wenn man nicht gerade auf einem Mehrkernsystem arbeitet, wird es nämlich>> durch einen Thread nicht effizienter>> Nochmal zum Mitschreiben: Es geht nicht darum ob es effizienter wird> denn nichts davon ist CPU-bound sondern es geht darum daß es mit einem> separaten Thread simpler, aufgeräumter, unkomplizierter, weniger Code> und einfacher wartbar wird.
Die meisten Programme scheitern ja schon daran, sauber aus einem
blockierten Aufruf heraus abzubrechen.
'Separation of concerns' geht wunderbar ohne Threads. Es geht auch
wunderbar mit Threads. Aber so wie der OT sein Problem bislang umrissen
hat, würde ich mich in diesem Fall nicht freiwillig Threads antun.
Vorallem 'synchronize' in Java ist immer wieder lustig. Selbst in der
Doku hat man das schon erkannt ('be very careful') ...
Nase schrieb:> würde ich mich in diesem Fall nicht freiwillig Threads antun.
Wieso antun? Ich empfinde Threads als eine nützliche Erweiterung meiner
Werkzeugkiste die ich gerne anwende wenn es sich anbietet (so wie im
vorliegenden Falle). Schließlich stellen Threads ja keinen Mehraufwand
dar (im Gegenteil) und übersichtlicher und modularer wirds dadurch auch
;-)
Bernd K. schrieb:> Wieso antun? Ich empfinde Threads als eine nützliche Erweiterung meiner> Werkzeugkiste die ich gerne anwende wenn es sich anbietet (so wie im> vorliegenden Falle). Schließlich stellen Threads ja keinen Mehraufwand> dar (im Gegenteil) und übersichtlicher und modularer wirds dadurch auch> ;-)
Und genau diese Vorgehensweise halte ich für nicht zielführend. Threads
sind nichts was man einfach mal so über eine Anwendung drüberstreut,
weil man das halt kann, sondern man sollte die nur einsetzen, wenn man
einen sehr guten Grund dafür hat. Und "meine Anwendung wird dadurch
modularer" ist definitiv kein Grund. Das kannst du ganz genau so auch
ohne Threads machen.
man könnte auch einfach nicht jedes mal das Rad neu erfinden, und eine
Biliothek verwenden die das schon mit threads macht..(was wohl eh alle
machen) (sowas wirds ja wohl auch für Qt geben?)
Sven B. schrieb:> Bernd K. schrieb:>> Sven B. schrieb:>>> Der Kernel füllt>>> doch so einen Buffer und schickt dir ein Event wenn der voll ist, oder?>>>> Nein.>> Sondern?
Du wartest auf das Event.
Bernd K. schrieb:>>> Nein.>>>> Sondern?>> Du wartest auf das Event.
Ich warte nicht aktiv auf das Event. Das steht in irgendeiner
Warteschlange und ich arbeite es ab wenn ich Lust dazu habe.
Sven B. schrieb:> Bernd K. schrieb:>>>> Nein.>>>>>> Sondern?>>>> Du wartest auf das Event.>> Ich warte nicht aktiv auf das Event. Das steht in irgendeiner> Warteschlange und ich arbeite es ab wenn ich Lust dazu habe.
Scroll mal nach oben: Es geht um "performant". Das ist inkompatibel mit
"wenn ich Lust dazu habe". Und wenn Du eh nur pollen willst wenn Du
gerade mal wieder ein bisschen Lust hast dann brauchst Du auch kein
Event.
Es geht um "performant" im Sinne von "weniger als 20ms Reaktionszeit".
Da ist es völlig ok, wenn das Event abgearbeitet wird, wenn die Event
Loop das nächste mal ausgeführt wird.
Sven B. schrieb:> Es geht um "performant" im Sinne von "weniger als 20ms Reaktionszeit".> Da ist es völlig ok, wenn das Event abgearbeitet wird, wenn die Event> Loop das nächste mal ausgeführt wird.
Ach, machs doch so Du willst.
OP hat sich wahrscheinlich eh schon längst verabschieded und ich bin
(und bleibe) ein Befürworter von modularem Design und loser Kopplung und
alles was autonom funktionieren kann soll auch autonom funktionieren und
schön gekapselt und austauschbar sein und wenn das Ding zur Erfüllung
seiner internen Aufgaben auf Events warten muss dann bekommt es eben mal
intern seinen eigenen Thread, warum denn auch nicht?
Man könnte fast meinen manchen Leuten wurde irgendwann in den letzten 4
Jahren eingetrichtert daß Nebenläufigkeit generell vom Teufel erfunden
wurde. Ist das etwa die JavaScript-Fraktion, jene Leute die spätestens
seit node überall nur noch Nägel für ihren (einen) Hammer sehen, die
erfolgreich für sich den Mangel zum Feature umdefiniert haben?
Mann mann mann, allein in der Zeit die dieser unselige Thread hier jetzt
schon diskutiert wird hätte man einen ganzen Threadpool schreiben
können.
Bernd K. schrieb:> OP hat sich wahrscheinlich eh schon längst verabschieded und ich bin> (und bleibe) ein Befürworter von modularem Design und loser Kopplung und> alles was autonom funktionieren kann soll auch autonom funktionieren und> schön gekapselt und austauschbar sein und wenn das Ding zur Erfüllung> seiner internen Aufgaben auf Events warten muss
... was, zum n-ten mal, überhaupt nichts mit Threads zu tun hat. Nichts.
Außer vielleicht dem letzten Teil mit den Events wenn die Events
irgendwie synchron ankommen. Was aber zum Beispiel bei Input-Events
nicht der Fall ist.
> dann bekommt es eben mal> intern seinen eigenen Thread, warum denn auch nicht?
"intern"? Den sehe ich sogar in meinem Task-Manager, wenn ich deine
Anwendung ausführe. Und warum nicht? Weil es im Zweifelsfall leicht mal
schlechtere Performance mit sich bringt (Kontextwechsel!) und die
Komplexität der Anwendung erhöht, wenn man einfach nur so ein paar
Threads über die Anwendung streut "weil man es kann".
Sven B. schrieb:> und die> Komplexität der Anwendung erhöht,
Zum n-ten Mal: nein. Siehe oben. Pollen ist inakzeptabel und
unperformant, da sind sich ja wohl alle einig. Was schlägst Du also vor?
Lass Dir Zeit mit der Antwort, ich hau mich jetzt aufs Ohr.
Bernd K. schrieb:> Pollen ist inakzeptabel und> unperformant, da sind sich ja wohl alle einig.
Nein, genau da ist sich keiner hier einig.
Einzig du allein hast Pollen grundlos als inakzeptabel hingestellt.
Nase schrieb:> Nein, genau da ist sich keiner hier einig.
Hier vielleicht nicht, in Fachkreisen jedoch schon. Und deshalb klinke
ich mich an dieser Stelle mal hier aus, das führt eh zu nichts.
Bernd K. schrieb:> Nase schrieb:>> Nein, genau da ist sich keiner hier einig.>> Hier vielleicht nicht, in Fachkreisen jedoch schon. Und deshalb klinke> ich mich an dieser Stelle mal hier aus, das führt eh zu nichts.
Oooh, in "Fachkreisen", soso!
Mit Polling hat das doch alles nix zu tun. Der Unterschied ob man das
Event-Handling im GUI-Thread macht oder nicht ist einfach nur der: im
ersten Fall kommt das Event (z.B. "neuer Kram aus dem Netzwerk
angekommen") in der Event-Loop vom GUI-Thread an; im zweiten Fall hast
du einen zweiten Thread, der selber eine Event Loop hat, und das Event
kommt dort an, und der Kernel wechselt zwischen den beiden Loops hin und
her. Das ist in dem Fall absolut kontraproduktiv.
Sven B. schrieb:> Das ist in dem Fall absolut kontraproduktiv.
Nein. Es ist kontraproduktiv irgendwelche internen Low-level Routinen im
Backend vom Frontend abhängig zu machen. Sowas trennt man sauber wenns
nicht gerade das absolut simpleste mal eben hingehackte Wegwerf-Programm
ist. Was machst Du wenn Du diese Protokollimplementierung morgen in ner
Konsolenanwendung brauchst? Oder für Linux mit GTK anstelle von
Irgendwas/Qt? Oder Windows? Oder als native Library fürn Android-Handy?
Willst Du dann das innerste nach außen stülpen nur damit die jeweilige
GUI direkt an den Sockets herumfuhrwerken um die Arbeit zu verrichten
die das Ding eigentlich ungefragt und klaglos eigenständig tun sollte?
Das will kein Mensch (oder ich zumindest jedenfalls nicht, wenn Du das
willst ist das Dein Problem).
OP hat gefragt ob er einen separaten Thread nehmen soll für die Dinge
die das GUI nichts anzugehen haben. Die Antwort ist ein klares Ja.
Bernd K. schrieb:> Sven B. schrieb:>> Das ist in dem Fall absolut kontraproduktiv.>> Nein. Es ist kontraproduktiv irgendwelche internen Low-level Routinen im> Backend vom Frontend abhängig zu machen.
Von welchen Low-Level-Routinen sprichst du? Qt Event Loop? Du kannst
keine Anwendung mit Qt schreiben ohne die Event Loop mit einzubeziehen.
Wenn deine Idee von Encapsulation ist, Netzwerkzugriff in einer
Qt-Anwendung zu machen, indem man vermeidet die Event Loop zu benutzen,
dann weiß ich auch nicht mehr was ich sagen soll.
> Sowas trennt man sauber wenns> nicht gerade das absolut simpleste mal eben hingehackte Wegwerf-Programm> ist.
Ja, klar, kein Widerspruch hier. Außer du meinst, dass man die
Implementierung vom Netzwerk-Code vom Framework trennt das man für den
Netzwerkzugriff verwendet, was vollkommen absurd wäre.
> Was machst Du wenn Du diese Protokollimplementierung morgen in ner> Konsolenanwendung brauchst?
Wie gesagt, kein Widerspruch hier. Hat aber nix mit Threads zu tun.
> Oder für Linux mit GTK anstelle von> Irgendwas/Qt?
Pech. Ungefähr genauso Pech wie wenn ich mir morgen überlege dass ich
meine Anwendung jetzt in Haskell schreiben will und mein Netzwerk-Code
aber schon in C ist. Du darfst hier gerne anderer Meinung sein, aber ich
persönlich werde niemals Code in einer Anwendung schreiben mit dem
Hintergedanken "wenn ich mal das Framework wechsle, was in jeder Zeile
meiner Anwendung verbaut habe, möchte ich diesen Code immer noch
verwenden können". Das ist in meiner Welt einfach grober Unfug.
> Oder Windows? Oder als native Library fürn Android-Handy?
Qt unterstützt beide Plattformen.
> OP hat gefragt ob er einen separaten Thread nehmen soll für die Dinge> die das GUI nichts anzugehen haben. Die Antwort ist ein klares Ja.
Die Antwort ist ein klares Nein, außer die Aufgaben sind
rechenzeitintensiv (und zwar im Sinne von "Rohdaten verarbeiten", nicht
"Rohdaten in ein Textfeld malen", dafür bringt der Thread nämlich
nichts) oder müssen von einer synchronen API geholt werden.
Sven B. schrieb:> Außer du meinst, dass man die> Implementierung vom Netzwerk-Code vom Framework trennt das man für den> Netzwerkzugriff verwendet
Nein. Ich meine daß man den Code für ein Netzwerkprotokoll nicht mit
einem GUI-Framework implementiert. Schon gar nicht mit so einem
Zweistelligen Multi-Magabyte-Monster wie Qt. Nicht jedes Problem ist ein
Nagel.
Qt ist nicht nur ein GUI-Framework. QtNetwork hängt nur von QtCore ab,
du kannst also QtNetwork verwenden ohne auch nur eine Zeile GUI-Code in
deiner Anwendung zu haben. Nicht QtNetwork zu verwenden wenn ich eh Qt
benutze halte ich für Schwachsinn, aber wenn dir das aufgrund
irgendwelcher theoretischen Argumente die in der Praxis keinerlei
Relevanz haben Spaß macht, ok.
Die GUI-Teile sind so Dinge wie QtWidgets, aber viele Komponenten von Qt
haben mit GUI nix zu tun.
Du predigst einerseits andauernd Sparsamkeit mit Einwänden über
irgendwelche ominösen Kontextwechsel (weil Du das Wort mal irgendwo in
nem anderen Zusammenhang aufgeschnappt hast) die bei der hier
betrachteten Aufgabenstellkung überhaupt nicht relevant sind (weil
nichts davon ist CPU-bound, alle beide Threads schlafen fast **immer**)
und andererseits willst Du selbst simpleste 10-Zeiler mit ein bisschen
leichtgewichtigem Socket-IO von Monster-Libraries wie Qt abhängig
machen.
Ich gebs auf. EOD.
Du hast eh eine Qt-Anwendung laufen. Jetzt hast du die Wahl ob du
einfach QtNetwork nimmst, was sich da schön einfügt, oder irgendeine
andere Netzwerk-Bibliothek (was für deine Anwendung übrigens erstmal
eine zusätzliche Abhängigkeit bedeutet!) und deren Event Loop (die haben
nämlich üblicherweise alle eine) irgendwie mit der Qt Loop
zusammenfrickelst (was überhaupt keinen Spaß macht, glaub mir). Ich
verstehe nicht, was an der Entscheidung schwer ist.
Sven B. schrieb:> oder irgendeine> andere Netzwerk-Bibliothek
Man braucht überhaupt keine "Netzwerk-Bibliothek" um einen socket zu
öffnen, zu lesen, zu schreiben oder select() zu verwenden. Das Zeug ist
alles in der libc schon drin. und in der Windows-API isses auch drin.
Gute Nacht.
Sven B. schrieb:> Ach so, die Windows-API. Das ist natürlich harte Konkurenz in Sachen> Entkopplung von unnötigen Dependencies.
Nicht bei Sockets. Wie ich schrieb sind sowohl sockets als auch send(),
recv() und select() auch in der libc und nahezu identisch in der Windows
API. Da reicht ein einziges ifdef und weniger als eine Bildschirmseite
Code um alle ein für allemal zu erschlagen.
in Zeiten von, kaufe ich mir 8 oder 16 CPU Kernen:
Also ICH nehme lieber eine MEGA-ÜBER-DRÜBER Library (z.b. Indy10)
das Problem ist nämlich: wenn morgen "jemand" (z.B. Chef) mit dem
Falsch Fuß aufsteht, und sagt: hey, wir machen das ab jetzt mit SSL !
dann kann ich sage: jo chef, mach ma mal 2 Zeilen code mehr und des
rennt.. ;-)
GUI in Windows funktioniert NUR mit Pollen (egal wie gern man das hat..)
in einen thread "auslagern" wird man also wohl am ehesten die
Bearbeitung der empfangenen Daten ... (damit dem Main-Thread immer schön
langweilig ist..)
(interessant wird das ganz eh erste wenn man einen Server hat, und
keinen Client.. um sich dann zu überlegen wie viele Threads mach ich bei
wievielen Verbindungen...)
Bernd K. schrieb:> Sven B. schrieb:>> Ach so, die Windows-API. Das ist natürlich harte Konkurenz in Sachen>> Entkopplung von unnötigen Dependencies.>> Nicht bei Sockets. Wie ich schrieb sind sowohl sockets als auch send(),> recv() und select() auch in der libc und nahezu identisch in der Windows> API. Da reicht ein einziges ifdef und weniger als eine Bildschirmseite> Code um alle ein für allemal zu erschlagen.
Naja, ich weiß auch nicht warum's jetzt plötzlich darum geht, warum die
Windows-API so viel toller ist um in einer Qt-Anwendung Netzwerk zu
implementieren als QtNetwork. Mit dem eigentlichen Thema hat das alles
nichts zu tun. Interessiert mich auch eher tangential, ich halte es für
groben Unfug, aber wenn du willst, bitteschön. Ich benutze doch nicht Qt
in meiner Anwendung und mache dann Netzwerk mit der Windows-API, weil
ich da ja "nur ein #ifdef" brauche damit es nicht komplett kacke sondern
nur ziemlich kacke ist.
Wenn Netzwerk so einfach wäre, dass man da nur "eine Bildschirmseite
Code" braucht, gäb's dafür keine Bibliotheken wie QtNetwork und Twisted.
Es ist halt nicht so einfach, siehe etwa das Beispiel mit SSL -- oder
nimm an, du willst HTTP machen oder sowas, auch nicht so einfach.
Außerdem musst du dir in dem Fall deine Event Loop selber schreiben und
wenn du dann z.B. einen Qt Slot in deinem Thread willst, wird das wieder
anstrengend.
Bernd K. schrieb:> Man braucht überhaupt keine "Netzwerk-Bibliothek" um einen socket zu> öffnen, zu lesen, zu schreiben oder select() zu verwenden. Das Zeug ist> alles in der libc schon drin. und in der Windows-API isses auch drin.
Ach, und ich dachte, gerade DU wolltest keine low-level-Frickelei.
Und du predigst doch auch dauernd, dass das alles nicht CPU-bound ist.
Das spricht ja noch viel mehr dafür, es in einem Thread zu tun, weil der
ja ohnehin fast nichts zu tun hat.
Modularisieren geht damit auch prima. Sogar noch einfacher, als wenn man
Threads kreuz und quer miteinander synchronisieren muss.
Nase schrieb:> als wenn man> Threads kreuz und quer miteinander synchronisieren muss.
Im vorliegenden Falle muss man gar nichts "kreuz und quer"
synchronisieren.
Bist Du als kleines Kind mal von nem Thread gebissen worden? Oder wie
sonst kommt diese irrationale Abneigung gegen ein x beliebiges
Allerweltspattern zustande mit dem niemand sonst auf der Welt Probleme
zu haben scheint? Gibts etwa noch andere grundlegende Paradigmen oder
Sprachelemente vor denen Du so eine irrationale Angst hast? Erzähl mal!
Bernd K. schrieb:> Oder wie> sonst kommt diese irrationale Abneigung gegen ein x beliebiges> Allerweltspattern zustande mit dem niemand sonst auf der Welt Probleme> zu haben scheint?
Ich hab' mit deiner Vorgehensweise zu dem Pattern auch Probleme, damit
sind wir immerhin schon zwei. Das ist genau wie mit diesen Design
Patterns, die wendet man nur an wenn man einen wirklich guten Grund
dafür hat, und nicht einfach so weil man es kann.
Sven B. schrieb:> Das ist genau wie mit diesen Design> Patterns, die wendet man nur an wenn man einen wirklich guten Grund> dafür hat, und nicht einfach so weil man es kann.
Als Grund sollte genügen: "ich möchte eine Software schreiben".
Wenn man eine Softwarearchitektur entwirft, sollten geeignete Design
patterns stets die Grundlage sein.
Boris P. schrieb:> sollten geeignete Design> patterns
Ja, geeignete.
Zu 'geeignet' gehört m.M.n. zum Beispiel auch, das jeweils
einfachst-mögliche Pattern zu implementieren. Das selbst ist wieder ein
Pattern, nämlich KISS.
Threads sind in diesem Fall ganz sicher nicht das einfachst-mögliche.
Bernd K. schrieb:> Bist Du als kleines Kind mal von nem Thread gebissen worden?
Nö, ich für meinen Teil habe Threads verinnerlicht.
> Oder wie> sonst kommt diese irrationale Abneigung gegen ein x beliebiges> Allerweltspattern zustande mit dem niemand sonst auf der Welt Probleme> zu haben scheint? Gibts etwa noch andere grundlegende Paradigmen oder> Sprachelemente vor denen Du so eine irrationale Angst hast? Erzähl mal!
Ich habe keine Angst vor Sprachelementen im Allgemeinen. Nur gegen
unbedachtes Einsetzen derselben.