Wieso lassen so viele Programme den Benutzer so lange warten?



  • Eisflamme schrieb:

    QT bietet Concurrent::run an: http://doc.qt.nokia.com/4.7-snapshot/qtconcurrentrun.html#run

    Es wird anscheinend automatisch auf einen Threadpool zurückgegriffen. Das ist für einmalige Funktionen eigentlich ganz chic.

    Es geht nicht darum einfach nur Funktionen in andere Threads auszulagern sondern um die Kommunikation und Datenübergabe zwischen Worker-Thread und UI-Thread.



  • Und wo liegt das Problem das Ergebnis, sobald es da ist, eben ins UI zu schreiben und, falls man die Daten weiterverwenden können soll für weitere Abfragen, diese eben vorher zu blocken?

    Mir geht es gerade wie gesagt vor allem um irgendwelche Abfragen. Die holt man, hat sie und verwendet sie dann. Es soll zwischendurch kein Dritter diese Daten manipulieren oder lesen können.



  • Eisflamme schrieb:

    Und wo liegt das Problem das Ergebnis, sobald es da ist, eben ins UI zu schreiben und, falls man die Daten weiterverwenden können soll für weitere Abfragen, diese eben vorher zu blocken?

    Das Problem ist, dass GUI Toolkits single-threaded und i.d.R. nicht threadsicher sind, das heißt das Update der Daten muss im UI Thread stattfinden, sonst kann's Ärger geben.
    Viele Programmierer sind eben zu faul (oder können es nicht) lange Tasks vernünftig auszulagern und dann die GUI korrekt zu aktualisieren. Darum machen viele das lieber direkt im UI Thread (z.B. im Button-klick-handler) und blockieren damit den UI Thread. Ergebnis: Oberfläche hängt aka "friert ein", falls der Task unerwartet lange dauert.



  • Ok, aber das ist doch immer noch kein Problem. Bei QT kann man halt so nen QFutureWatcher nutzen, setzt dem halt das erstellte Future-Objekt. Wenn das Ding fertig ist, erhält man ein Signal, verbindet das zu nem Slot vom Haupt/UI-Thread und setzt dann die Daten. Man muss eben davon ausgehen, dass das UI nicht threadsafe ist und es entsprechend behandeln. Aber das ist doch kein Hexenwerk, wenn man sich ein wenig mit Threads beschäftigt, oder? Selbst mir ist das mittlerweile klar und ich beschäftige mich erst seit einer Woche oder so mit dem Thema (und das auch leider nicht sehr intensiv).

    Was Du da beschreibst ist ja genau das, was mich wundert / was ich nicht gut finde. Also liegt es am Skill, der fehlt? Denn wenn man so was wie QT sowieso nutzt, braucht man nicht mehr als ein kurzes Hineinblicken in die Doku, um das vermeintliche Problem zu lösen - IMO. Vielleicht übersehe ich auch noch weitere Probleme?



  • Dann muss die ganze Geschäftslogik threadsicher sein. Wenn der GUI Thread blockiert ist und grundsätzlich alles im GUI Thread passiert, dann ist das ganze single threaded. Wenns nicht mehr im GUI Thread passiert, könnte der Benutzer was anderes anklicken und dann muss man überall für threadsicherheit sorgen und das ist dann wohl vielen zu umständlich. Grundsätzlich spricht aber natürlich nichts dagegen. Nur gibts es halt sehr viel Legacy Code, es gibt immer viel zu tun, und das alles umzubauen und zu testen hat halt meist nicht Prio A.



  • Es geht ja auch ganz billig 😉

    Bei QT einfach

    QCoreApplication::processEvents();
    

    in die Schleife der aufwendigen Berechnung setzen. Schon wird die Ereignisschlage der GUI wieder bearbeitet und die GUI verharrt nicht ohne Reaktion.



  • Hallo,

    Mann, was hast Du denn für Probleme? Wer oder was lässt Dich denn so lange warten? Was für lahme Kisten setzt Du denn ein?

    Mal eine andere Geschichte die dazu passt:

    Vor vielen Jahren (OK ich geb's zu es waren ein paar mehr) habe ich in meinem (damals) jugendlichen Leichtsinn ein Programm geschrieben um die Fakultät von 1000000 zu berechnen. Mich hat es einfach geärgert, daß mein Taschenrechner ab 79 nur noch Error geliefert hat.

    Auf das Ergebnis habe ich 7 Tage gewartet. Habe mal soeben spaßeshalber das gleiche mit meiner aktuellen Maschine ausprobiert. Was soll ich sagen: Das Ergebnis wurde schon geliefert, da hatte ich die Entertaste zum Starten des Programms noch nicht richtig losgelassen. Ich glaubte zuerst an einen Fehler und habe mir dann extra meine Aufzeichnungen von damals aus dem Archiv geholt und verglichen. Es war exakt das gleiche Ergebnis.

    Jetzt beschwer dich bloß nicht nochmal über Deine lahme Krücke. Du weißt nicht, was eine lahme Krücke ist.

    mfg Martin


  • Mod

    Hast du auch das gleiche Programm benutzt? Die Geschichte klingt nicht sehr glaubwürdig, kein Rechner sollte jemals mehrere Tage benötigen, um seinen gesamten Hauptspeicher mit signifikanten Stellen von 1000000! zu füllen. Eigentlich sollte sich der Zeitbedarf sogar so ungefähr die Waage halten über alle Epochen hinweg, da die Zeit wichtig ist, in der der Rechner Daten von der Länge seines Hauptspeichers verarbeiten kann. Und falls es nur auf kleine, feste Anzahl Stellen signifikant sein soll, schafft das sogar ein Computer aus den 80ern in Sekunden bis Minuten.



  • Vielleicht hat er den rekursiven Algorithmus aus der Mottenkiste geholt und der Compiler konnte ihn nicht auflösen.

    Edit: Wobei das Ding dann ne Menge Stack gebraucht hätte. 🤡



  • SeppJ schrieb:

    Hast du auch das gleiche Programm benutzt? Die Geschichte klingt nicht sehr glaubwürdig, kein Rechner sollte jemals mehrere Tage benötigen, um seinen gesamten Hauptspeicher mit signifikanten Stellen von 1000000! zu füllen. Eigentlich sollte sich der Zeitbedarf sogar so ungefähr die Waage halten über alle Epochen hinweg, da die Zeit wichtig ist, in der der Rechner Daten von der Länge seines Hauptspeichers verarbeiten kann. Und falls es nur auf kleine, feste Anzahl Stellen signifikant sein soll, schafft das sogar ein Computer aus den 80ern in Sekunden bis Minuten.

    So Du glaubst mir nicht?

    Nun gut ein paar mehr Infos:

    Am großen "Computer-Bild" Vergleichstest nahmen teil:

    • CBM 3032 - 6502 8-Bit CPU - 1 Kern - 1 Thread - 1 MHz Takt - 32 KB RAM - Commodore Basic - Baujahr ca. 1978
    • Dell Vostro 460 - i7-2600 64-Bit CPU - 4 Kerne - 8 Threads - 3,4 GHz Takt - 16 GB Ram - Borland C++ 5.02 - Baujahr 2011

    Das Programm hat natürlich nicht die Fakultät von 1000000 auf alle ca. 5,5 Mio Stellen berechnet, dazu wäre der alte Rechner ohne Festplatte gar nicht in der Lage gewesen.

    Den BASIC Quelltext von damals habe ich nicht mehr, den von gestern gibt es hier:

    #include <stdio.h>
    #include <math.h>
    
    int main( void )
    {
    	double			mantisse = 1.0;
    	unsigned long	exponent = 0;
    	long			i;
    	int				exp;
    
    	for( i=2; i<=1000000; i++ )
    	{
    		mantisse *= i;
    
    		exp = log10( mantisse );
    		if( exp )
    		{
    			exponent += exp;
    			mantisse /= pow10( exp );
    		}
    	}
    
    	printf( "%f %ld\n", mantisse, exponent );
    
    	return 0;
    }
    

    Mit den 7 Tagen, muß ich zugeben kann es schon sein, daß ich ein wenig übertrieben habe. Es ist ja schon viele Jahre her. Es waren aber auf jeden Fall mehrere Tage.

    mfg Martin



  • Die BilligeAntwort schrieb:

    Es geht ja auch ganz billig 😉

    Bei QT einfach

    QCoreApplication::processEvents();
    

    in die Schleife der aufwendigen Berechnung setzen. Schon wird die Ereignisschlage der GUI wieder bearbeitet und die GUI verharrt nicht ohne Reaktion.

    Wenn die Funktion das tut, was ich ihrem Namen nach vermute, handelt man sich überall Reentrancy-Probleme ein.



  • µ schrieb:

    Wenn die Funktion das tut, was ich ihrem Namen nach vermute, handelt man sich überall Reentrancy-Probleme ein.

    Das sieht auch für mich wie das Pendant zum berüchtigten Application.DoEvents() aus 😃 Ein Hoch auf die gefakte Parallelität.



  • GPC schrieb:

    µ schrieb:

    Wenn die Funktion das tut, was ich ihrem Namen nach vermute, handelt man sich überall Reentrancy-Probleme ein.

    Das sieht auch für mich wie das Pendant zum berüchtigten Application.DoEvents() aus 😃 Ein Hoch auf die gefakte Parallelität.

    Genau das.
    Mein Vorgänger hat überall Application.DoEvents() verwendet. Auch in DLLs zur Hardwareansteuerung. Ich bin diesem Menschen nie begegnet und trotzdem hasse ich ihn 😉



  • µ schrieb:

    Die BilligeAntwort schrieb:

    Es geht ja auch ganz billig 😉

    Bei QT einfach

    QCoreApplication::processEvents();
    

    in die Schleife der aufwendigen Berechnung setzen. Schon wird die Ereignisschlage der GUI wieder bearbeitet und die GUI verharrt nicht ohne Reaktion.

    Wenn die Funktion das tut, was ich ihrem Namen nach vermute, handelt man sich überall Reentrancy-Probleme ein.

    Ich habe es gerade getestet.
    Ich weiß nicht wieso es so funktioniert aber ein auslösendes Signal startet eine Methode die sich noch in einer Berechnung befindet erst dann erneut, wenn sie abgearbeitet ist bei Qt. Es wird auch maximal ein weiter Aufruf gespeichert.

    Wenn also während der Ausführung ein Signal entsteht dass die selbe Methode nochmal aufgerufen werden soll, passiert so lange nichts, bis die Methode abgearbeitet ist. Der Aufruf findet erst danach statt. Aber auch nur einmal, egal wie viele Signale inzwischen produziert worden sind.

    Ich habe es mit Qt 4.7.4 getestet.



  • Nachtrag:

    Es scheint irgendwie betriebsystem abhängig zu sein. Nur bei Windows 7 habe ich keine Selbstaufrufe während die Methode noch läuft, bei Windows XP schon.
    Also QCoreApplication::processEvents(); vorsichtig verwenden 😉



  • Um nochmal auf das Grundlegende Thema zurück zu kommen:

    Es bietet sich halt oft an, längere Operationen nicht in Asynchron auszuführen. Zum einen wie schon genannt, da es die Entwicklung vereinfacht, zum anderen aber auch, da es für den Benutzer am Ende egal ist, ob er die Anwendung nicht verwenden kann, weil sie für den Zeitraum nicht reagiert, oder weil die relevanten Steuerelemente gesperrt sind.


  • Administrator

    inflames2k schrieb:

    ..., zum anderen aber auch, da es für den Benutzer am Ende egal ist, ob er die Anwendung nicht verwenden kann, weil sie für den Zeitraum nicht reagiert, oder weil die relevanten Steuerelemente gesperrt sind.

    Würde ich so nicht sagen. Die meistens wissen es nur nicht, dass es auch schneller gehen würde und nehmen es dann halt als ein Ärgernis hin.

    @Eisflamme,
    Mach einfach mal ein paar Beispiele durch, was Multithreading betrifft und dann wirst du schnell mal begreifen, wieso dies nicht alles so einfach ist. Ich habe gerade eben in Android was machen müssen, wo Bilder asynchron aus dem Inet geladen werden und auch zum Teil im Voraus. Wenn der User zum nächsten Bild will, musst du prüfen, ob dieses womöglich bereits schon geladen wird oder schon geladen wurde oder noch gar nicht in Auftrag gegeben wurde. Oder gab es einen Fehler und sollte nochmals ausgeführt werden? Und wie behandelst du Fehler in einer solche Ausführung? Wie meldest du sie dem Benutzer? usw. usf.
    Multithreading verkompliziert das Problem um ein Vielfaches.

    Und nicht zu vergessen sind auch solche Dinge:
    http://magazin.c-plusplus.net/artikel/Der%20Dreisatz%20l%FCgt

    Nicht alles lässt sich parallelisieren.

    Grüssli



  • die Frage ist aber, wie viel vom Parallelisierungsproblem auf die Kappe der Programmiersprachen selbst geht.

    Programmiersprachen wie C++ stammen aus Zeiten, als Parallelisierung noch nicht das Thema war. Ergo keine optimale Formalisierung von nebenläufigen Vorgängen.

    ich kann mir vorstellen, daß sich das in Zukunft nolens volens ändern wird. Sprachmittel zur einfachen Modellierung von nebenläufigen Prozessen werden vielleicht mal das feature sein, so wie heute Klassen und geschweifte Klammern. erlang fällt mir hier spontan ein.



  • Tja, die perfekte Art (sofern sie exisiert) parallele Ausführungsmöglichkeiten zur Verfügung zu stellen ist halt (noch?) nicht gefunden worden.

    Ist aber ein aktives Forschungsgebiet.



  • !rr!rr_. schrieb:

    die Frage ist aber, wie viel vom Parallelisierungsproblem auf die Kappe der Programmiersprachen selbst geht.

    Programmiersprachen wie C++ stammen aus Zeiten, als Parallelisierung noch nicht das Thema war. Ergo keine optimale Formalisierung von nebenläufigen Vorgängen.

    ich kann mir vorstellen, daß sich das in Zukunft nolens volens ändern wird. Sprachmittel zur einfachen Modellierung von nebenläufigen Prozessen werden vielleicht mal das feature sein, so wie heute Klassen und geschweifte Klammern. erlang fällt mir hier spontan ein.

    Gabs alles Schon in Lisp. Ada faellt mir ein. Haskell hat interessante Ansaetze. Und zu guter Letzt: Vhdl bzw. FPGAs.


Anmelden zum Antworten