Wie viele Threads sollte man nutzen?



  • rapso schrieb:

    saubere kapselung ist halt der erste schritt, wenn man es durchziehst, dann kann man auch dafuer sorgen dass die UI responsiv ist.
    UI in einen thread zu packen, ist eher eine notloesung, da die implementierung einer sauberen loesung im nahinein unverhaeltnis lange dauern wuerde.

    Also vielleicht sollte man hier auch nochmal zwischen Spiel und Windows-Anwendung unterscheiden. Was bedeutet es denn eine GUI responsive zu halten?

    a) In Windows-Anwendungen, dass weiterhin Windows-Nachrichten verarbeitet werden. Entweder hat man dann in seinem "Arbeites-Code" sowas schreckliches wie "ProcessMessages" oder man lagert halt die Arbeit aus, womit man dann die GUI auf einem seperaten Thread laufen hat. Von daher finde ich sowas "per Design" von vorneherein zu implementieren ist keine Notlösung.

    b) Spiele. Da ist die GUI eigentlich ein Teil der normalen Spiel-Szene, die als Overlay über den Rest gerendert wird. Dies ist also Teil des Renderings und normalerweise da zu finden, wo man auch seinen restliche GameLoop bearbeitet. Wie ich das im Falle von Spielen machen würde, hatte ich ja schon geschrieben. Es gäbe da jedenfalls keinen explusiven GUI Thread.

    Im Allgemeinen stimme ich Dir aber zu, dass eine vernünftige Architektur Vorraussetzung ist.



  • Jop, denke ich auch, dass man das trennen sollte. Bei "normalen" Anwendungen dienen Threads eigentlich eher dazu, das Programm "responsive" zu halten. Man lagert also die gesamte I/O aus, und eventuell "schwere" Berechnungen, die im Hintergrund gemacht werden. Bei Spielen geht das eher in Richtung parallele Verarbeitung aus Performancegründen. Man kann den GUI Kram zwar auch entkoppeln (Netzwerk, I/O), aber das ist da eben nur der halbe Kuchen. Physik parallel zu berechnen o.Ä. drängt sich eben nicht so auf, und bedarf ganz anderer Überlegungen. Und bei einem Spiel hilft es auch nur bedingt die UI "responsive" zu halten, wenn alles andere hängt. Wobei, wenn ich so darüber nachdenke. Vielleicht ist das gar keine so schlechte Idee. Hm.


  • Mod

    Morle schrieb:

    rapso schrieb:

    saubere kapselung ist halt der erste schritt, wenn man es durchziehst, dann kann man auch dafuer sorgen dass die UI responsiv ist.
    UI in einen thread zu packen, ist eher eine notloesung, da die implementierung einer sauberen loesung im nahinein unverhaeltnis lange dauern wuerde.

    Also vielleicht sollte man hier auch nochmal zwischen Spiel und Windows-Anwendung unterscheiden. Was bedeutet es denn eine GUI responsive zu halten?

    naja, ich ging bei UI eh von anwendungen aus, nicht spielen, bisher kam bei spielen niemand auf diese idee sie in einem anderen thread zu verarbeiten...naja... noch nicht *Seufz*, fuehle dich angestarr @cooky451 🤡

    a) In Windows-Anwendungen, dass weiterhin Windows-Nachrichten verarbeitet werden. Entweder hat man dann in seinem "Arbeites-Code" sowas schreckliches wie "ProcessMessages" oder man lagert halt die Arbeit aus, womit man dann die GUI auf einem seperaten Thread laufen hat. Von daher finde ich sowas "per Design" von vorneherein zu implementieren ist keine Notlösung.

    es ist eine notloesung die durch 'bei mir lief das toll und einfach' zu einer 'packt alle eure UI in einen thread'-loesung propagiert wurde. es macht keinen sinn eine UI in einen thread zu packen, wenn der funktionsteil in einem anderen thread arbeitet und nicht reagiert. das ist als ob man dem fahrer erlauben wuerde seinen lenker wild drehen zu koennen waehrend sein fahrzeug geradeaus faehrt, gibt sicher einen kurzen moment an dem man zaghaft bis voller motivation dran dreht, aber es aendert doch nichts. es traegt eher zum gegenteil bei, dadurch dass die 'worker' immer weiter im hintergrund sind, wird die applikation weniger responsive, wenn auch die UI in einem thread arbeitet. z.b. koennen manche textverarbeitungsprogramme super fluessig bewegt werden und menues aufklappen, rechtschreibkorrektur tingelt aber sekunden hinterher, mein nokia 3210 konnte mit t9 sowas in echzeit (und ich denke nicht, dass die suchmenge derart gestiegen ist, dass ein 3GHz PC heutzutage 1s brauchen wuerde).

    Ich denke threads in applikationen sind gut in z.b. eclipse, wo ein thread (bzw prozess) abseits der IDE immer mitcompiliert, aber es ist eben keine UI-vom-rest-dank-thread-entkopplung.

    vielleicht kannst du mir ein beispiel geben wo es sehr sinnig ist und nicht anders sauber machbar ist.

    b) Spiele. ...

    hmm, ja, da hatte ich nie in bezug auf UI gesprochen, spiele entkopplen aber network, input, file i/o, sound oft durch threads, lazy man solution(tm).
    wobei ich mir nicht sicher bin, ob es wirklich lazy man ist, oder weil viele programmierer von frueher kommen, wo es fuer sowas interrupts gab und man natuerlich einen interrupt haendler hatte, jedoch ist es dann ein missverstaendniss von modernen betriebssystemen. der interrputhaendler ist ja quasi immer noch da, aber das OS regelt es und steckt es in buffer.
    frueher war es halt:
    interrupt->interruptthread der es in buffer kopiert->logik die es aus dem interrputhaendler-buffer kopiert&verarbeitet
    jetzt sollte es sein:
    interrupt->interruptthread vom OS der es in buffer kopiert->logik die es aus den OS buffern kopiert&verarbeitet
    leider ist es oft:
    interrupt->interruptthread vom OS der es in buffer kopiert->socket/input thread vom spiel der es in einen internen buffer kopiert -> logik die es aus den internen buffern kopiert&verarbeitet

    @cooky451
    hoer auf mich hier fertig zu machen, ui thread 🤡
    wobei das auf konsolen und handies ja in etwa so ist, afaik kann auf der xbox dein spiel sterben, du kannst aber noch den home button druecken und bekommst das menue eingeblendet. bei android/iOS scheint mir das auch so zu sein. lustigerweise machen es manche spiele genau andersrum, UI bekommt weniger updates als das ganze spiel, da sie sich eh kaum bewegt und kaum jemand merkt, ob da jetzt 30fps oder 10fps auf der UI sind, solange der rest fluessig ist. (wenn man ueberall nach einzelnen ms sucht, ist selbst das rendern der UI, besonders flash-artig, nicht gerne gesehen).



  • Ich denke du siehst das falsch. Wenn Systeme eh kaum kommunizieren müssen, (und sowas wie eine queue reicht), dann dürfte der Overhead von Threads kaum zu spüren sein. Das Argument mit dem 1 Thread/Client bei high performance Servern gilt nicht, davon wurde nie gesprochen. Man produziert ja keine 1000, sondern vielleicht 8 Threads, und deren Anzahl kann man sehr genau kontrollieren. Dass die Berechnungen in einem "hintergrund"-Thread wesentlich verlangsamt werden denke ich auch nicht. Die Checks werden nicht mal 1% Performance kosten und wenn doch, war die Berechnung entweder trivial, oder man hat etwas falsch gemacht.* Siehst du asynchrone OS-API Aufrufe eigentlich als Thread an? Denn letztlich ist das ja nichts anderes, nur liegt der Thread beim System. Und Windows selbst lässt durchgängig so etwa 600 Threads laufen, sooo schlimm können die da doch wohl nicht sein. 😉

    * Bedenke auch hier: 1 GUI, 1 Hintergrund Thread! Nicht 1 Thread pro Berechnung! Edit: Oder besser: Ein Producer, Ein Consumer. Wie viele Threads das dann genau sind, ist eigentlich nebensächlich.



  • Siehst du asynchrone OS-API Aufrufe eigentlich als Thread an? Denn letztlich ist das ja nichts anderes, nur liegt der Thread beim System.
    

    Denkst du? Zb asynchrones Lesen von einer Datei heißt ja im Optimalfall dass das OS eine DMA-Aktion startet und den Auftraggeber informiert sobald der Controller seinen ganzen Krempel in den RAM geschrieben hat. Da hat das OS/die CPU ja 0.0 Rechenaufwand dabei.



  • rapso schrieb:

    es ist eine notloesung die durch 'bei mir lief das toll und einfach' zu einer 'packt alle eure UI in einen thread'-loesung propagiert wurde. es macht keinen sinn eine UI in einen thread zu packen, wenn der funktionsteil in einem anderen thread arbeitet und nicht reagiert. [...] es traegt eher zum gegenteil bei, dadurch dass die 'worker' immer weiter im hintergrund sind, wird die applikation weniger responsive, wenn auch die UI in einem thread arbeitet.

    [...]
    vielleicht kannst du mir ein beispiel geben wo es sehr sinnig ist und nicht anders sauber machbar ist.

    Also wenn für dich "Responsiveness" das absolute Ziel ist, von dem nicht abgewichen werden darf, dann hast Du Recht. Für mich spielen aber auch andere Dinge eine Rolle: Der Benutzer darf gerne sein Programmfenster noch verschieben dürfen, während irgendeine komplizierte Berechnung läuft. Gerne er auch die lange Berechnung abbrechen dürfen - auch das geht nur mit einer wenigstens minimal bedienbaren GUI - Responsiveness ist hier zweitrangig.

    Man muss also Eingaben verarbeiten (bei Windows in Form von Messages) während man "Arbeitet".
    Wie ich schon sagte läuft das in der "Arbeit" darauf hinaus, immer mal wieder ProcessMessages aufzurufen. Man koppelt also "GUI-Arbeit" ganz direkt in seine "Berechnungs-Arbeit" rein (wo bleibt da die von dir angesprochene "saubere Architektur"?). Schlimmer noch, man hat eigentlich Calls von einer niederwertigen Schicht in eine viel höhere Schicht rein. Weiterhin setzt es vorraus, dass man seine Arbeit überhaupt in kleine Pakete teilen kann, um ProcessMessages aufrufen zu können. Nutzt einem wenig, wenn man in einer synchronen Betriebssystemfunktion festhängt.
    Oder man kann einfach beides in verschiedene Threads packen und nutzt damit die Preemption von seinem OS, kann Layer sauber trennen und muss sich auch keine Gedanken um synchrone OS-Funktionen machen, etc.

    Ich hoffe das reicht dir als Beispiel.

    rapso schrieb:

    hmm, ja, da hatte ich nie in bezug auf UI gesprochen, spiele entkopplen aber network, input, file i/o, sound oft durch threads, lazy man solution(tm).
    wobei ich mir nicht sicher bin, ob es wirklich lazy man ist, oder weil viele programmierer von frueher kommen, wo es fuer sowas interrupts

    Ich denke zwar nicht, dass Leute gerne Threads benutzen weil sie früher mit IRQs zu tun hatten, aber will darauf jetzt nicht weiter eingehen, weils dann doch zu sehr offtopic wird 😉



  • Ethon schrieb:

    Denkst du? Zb asynchrones Lesen von einer Datei heißt ja im Optimalfall dass das OS eine DMA-Aktion startet und den Auftraggeber informiert sobald der Controller seinen ganzen Krempel in den RAM geschrieben hat. Da hat das OS/die CPU ja 0.0 Rechenaufwand dabei.

    Von Rechenaufwand hat niemand gesprochen, nen Thread brauchst du trotzdem dafür.



  • cooky451 schrieb:

    Ethon schrieb:

    Denkst du? Zb asynchrones Lesen von einer Datei heißt ja im Optimalfall dass das OS eine DMA-Aktion startet und den Auftraggeber informiert sobald der Controller seinen ganzen Krempel in den RAM geschrieben hat. Da hat das OS/die CPU ja 0.0 Rechenaufwand dabei.

    Von Rechenaufwand hat niemand gesprochen, nen Thread brauchst du trotzdem dafür.

    Sagen wir es mal so, du brauchst keinen einzigen Thread mehr als wenn das Feature nicht vorhanden wäre.


  • Mod

    cooky451 schrieb:

    Ich denke du siehst das falsch. Wenn Systeme eh kaum kommunizieren müssen, (und sowas wie eine queue reicht), dann dürfte der Overhead von Threads kaum zu spüren sein.

    worauf beziehst du dich damit gerade, mir fehlt der kontext um antworten zu koennen. letzter beitrag von mir bezog sich nicht auf kommunikationsaufwand, glaube ich.

    Siehst du asynchrone OS-API Aufrufe eigentlich als Thread an? Denn letztlich ist das ja nichts anderes, nur liegt der Thread beim System.

    ich glaube das hatte ich damit beantwortet gehabt:

    frueher war es halt:
    interrupt->interruptthread der es in buffer kopiert->logik die es aus dem interrputhaendler-buffer kopiert&verarbeitet
    jetzt sollte es sein:
    interrupt->interruptthread vom OS der es in buffer kopiert->logik die es aus den OS buffern kopiert&verarbeitet
    leider ist es oft:
    interrupt->interruptthread vom OS der es in buffer kopiert->socket/input thread vom spiel der es in einen internen buffer kopiert -> logik die es aus den internen buffern kopiert&verarbeitet

    Und Windows selbst lässt durchgängig so etwa 600 Threads laufen, sooo schlimm können die da doch wohl nicht sein.

    wie ich schon zum thema starcraft sagte, wenn du da 40threads hast und die sidn einfach nur idle, ist es performance maessig nicht schlimm, design maessig ist es einfach nur traurig.
    beim OS darfst du das nicht direkt 1:1 anwenden, denn dein OS hat schonmal 65536 "threads" dadurch dass es verschiedene interrupts gibt. wenn du mal ein OS programmiert hast, oder unter DOS einen treiber, dann weisst du, wie das laeuft. unter DOS hies das auch nicht 'thread' sondern TSR (terminate but stay resistent), was soviel bedeutet, dass du dein program beendest, aber speicher 'leakst' auf den ein hardware interrupt zeigt und wo du binary reinkopiert hattest. dass protected mode systeme dafuer Threads erstellen ist eher ein sicherheits bedingtes, als design bedingtes system,... ich glaube der post wird zu lang wenn ich das ausfuehre.

    * Bedenke auch hier: 1 GUI, 1 Hintergrund Thread! Nicht 1 Thread pro Berechnung! Edit: Oder besser: Ein Producer, Ein Consumer. Wie viele Threads das dann genau sind, ist eigentlich nebensächlich.

    nein, es ist kein producer konsumer system, wenn leute threads einbauen fuer UI, dann ist es meistens ein entkoppelter "reponsibility" thread. im hintergrund kann ein producer-konsumer system laufen z.b. beim browser, aber dann scrollst du mit dem UI thread und wenn das system im hintergrund mit anderen dingen beschaeftigt ist, zieht dir der sehr responsive Internet Explorer oder auch safari auf dem iPad einfach nur schlieren bzw ein leeres bild hoch und dann kannst du manchmal etwas warten bis das system im hintergrund merkt, dass ein screenupdate noetig ist und zeichnet ein neues bild.
    ein producer consumer system braeuchte keinen 'thread', denn jedes moderne OS ist schon ein producer, alle eingaben liegen in einer message queue, dein program muss sie nur aufgreifen und als consumer verarbeiten. im konkreten fall eines browsers, wuerdest du deinen 'worker threads' die aufgabe erteilen das bild zu verschieben und fehlende stellen neu zu zeichnen.
    wenn dein system gut laeuft, ist es responsiv ohne UI thread, wenn es schlecht laeuft, sieht der user auch mit UI thread erstmal nichts.



  • Ethon schrieb:

    cooky451 schrieb:

    Ethon schrieb:

    Denkst du? Zb asynchrones Lesen von einer Datei heißt ja im Optimalfall dass das OS eine DMA-Aktion startet und den Auftraggeber informiert sobald der Controller seinen ganzen Krempel in den RAM geschrieben hat. Da hat das OS/die CPU ja 0.0 Rechenaufwand dabei.

    Von Rechenaufwand hat niemand gesprochen, nen Thread brauchst du trotzdem dafür.

    Sagen wir es mal so, du brauchst keinen einzigen Thread mehr als wenn das Feature nicht vorhanden wäre.

    Bei einem sychronen Aufruf passiert alles auf deinem Thread. Bei einem asynchronen Aufruf erfolgt der Callback der asynchronen Routine auf einem Kernel-Thread oder aber man schickt dir eine Windows Nachricht. Irgendjemand hat aber diese Nachricht im Kernel auch erzeugen müssen. Da das nicht auf deinem Thread passiert ist, hat das also ein Kernel-Thread getan.

    Ein DMA Controller oder was auch immer informiert deine *CPU* (nicht OS), über eine Interruptleitung. Dadurch wird eine Interrupt-Service Routine ausgeführt (nach Rapsos Defintion soll das wohl der Interrupt-Thread sein). ISR sind aber eigentlich Threads (zumindest nicht im OS Sinne), denn mit Threads ist ein Kontext assoziiert, mit einer ISR erstmal nicht.
    Es würde mich schwer wundern, wenn dein Asynchroner Callback direkt innerhalb der ISR ausführt werden würde. Damit könntest dein ganzes System zum Stillstand bringen, denn während ein Interrupt verarbeitet wird, kann normalerweise kein anderer verarbeitet werden. Deswegen wird in der ISR der oben genannte Kernel Thread informiert, dass jetzt Daten vorliegen. Der macht dann dein Callback.



  • Morle schrieb:

    ISR sind aber eigentlich Threads (zumindest nicht im OS Sinne), denn mit Threads ist ein Kontext assoziiert, mit einer ISR erstmal nicht.

    Es muss natürlich heissen:
    ISR sind aber eigentlich keine Threads (zumindest nicht im OS Sinne), denn mit Threads ist ein Kontext assoziiert, mit einer ISR erstmal nicht.



  • @rapso: Wenn nicht Kommunikation, wo ist dann der Punkt? OS Scheduling? Ich verstehe auch nicht wirklich, wie du das dann zusammenbasteln willst mit einer einzigen queue. Wenn da jetzt 4 rechenintensive Aufgaben drin stehen, und dahinter { process_gui_stuff(); }, hängt doch alles nur noch? Sicher, die Aufgaben werden 1 ms schneller fertig, aber das ist es doch wohl kaum Wert, wenn der User während der Zeit nichts machen kann. Wenn der GUI Thread durchgängig bei GetMessage() hängt und nur nach "hinten" durchleitet, sollte das wohl kaum Probleme geben. Ja, man verlässt sich auf das OS, aber dafür ist es doch da. Ich versuche wirklich zu sehen wo jetzt das Problem ist, aber ich verstehe es einfach nicht.


  • Mod

    Morle schrieb:

    rapso schrieb:

    es ist eine notloesung die durch 'bei mir lief das toll und einfach' zu einer 'packt alle eure UI in einen thread'-loesung propagiert wurde. es macht keinen sinn eine UI in einen thread zu packen, wenn der funktionsteil in einem anderen thread arbeitet und nicht reagiert. [...] es traegt eher zum gegenteil bei, dadurch dass die 'worker' immer weiter im hintergrund sind, wird die applikation weniger responsive, wenn auch die UI in einem thread arbeitet.

    [...]
    vielleicht kannst du mir ein beispiel geben wo es sehr sinnig ist und nicht anders sauber machbar ist.

    Also wenn für dich "Responsiveness" das absolute Ziel ist, von dem nicht abgewichen werden darf, dann hast Du Recht. Für mich spielen aber auch andere Dinge eine Rolle: Der Benutzer darf gerne sein Programmfenster noch verschieben dürfen, während irgendeine komplizierte Berechnung läuft. Gerne er auch die lange Berechnung abbrechen dürfen - auch das geht nur mit einer wenigstens minimal bedienbaren GUI - Responsiveness ist hier zweitrangig.

    abbrechen? schon wirft sich die frage auf, "wie" brichst du ab? du kannst nicht einfach einen thread stoppen und killen, das gebe leaks und unvorhergesehene seiteneffekte (z.b. koennte ein thread gerade in einer critical section sein).
    du musst also eine interaktionsmoeglichkeit einbauen, einfach nur ein UI thread wuerde das nicht bringen. aber dann, wenn der hintergrundthread abgebrochen werden kann, muss er irgendwie eine granularitaet beigebracht bekommen das zu tun. im schlechten fall ruft er von 100 stellen im code sein "IsRunning()" auf und bei false versucht es ohne memory leaks den aufrufsstack hoch zu kommen, manche werfen sich dann auch einfach eine exception. aber richtig gut ist es wenn man die arbeit dieses threads schon in kleine aufgaben aufteilt, vielleicht sogar mittels einer job-queue. dann kann das system nach jedem kleinen job abfragen, ob es noch weiter geht.
    und schwubs kannst du an dieselbe stelle die abfrage der event-queue vom OS einbauen und verarbeiten. macht der user kein input, laeuft alles wie immer, gibt es input, wuerde sich das system drum kuemmern, auf diese weise brauchst du nichtmal threads (wenn es nur um entkoplung geht), der user hat dennoch den vollen kompfor.

    Man muss also Eingaben verarbeiten (bei Windows in Form von Messages) während man "Arbeitet".
    Wie ich schon sagte läuft das in der "Arbeit" darauf hinaus, immer mal wieder ProcessMessages aufzurufen. Man koppelt also "GUI-Arbeit" ganz direkt in seine "Berechnungs-Arbeit" rein (wo bleibt da die von dir angesprochene "saubere Architektur"?).

    hab ich drueber beschrieben, wo bleibt auf der anderen seite deine entkopplung, wenn du ueberall im code z.b. drauf testen darfst, ob 'cancel' geklickt wurde? welche responsibilitaet erfaehrt der user? welche quality of service in anbetracht dessen, dass er ja mal ein program anders nutzen kann als der programmierer der seine abfragen eingebaut hat.
    und das ist kein auswuchs meiner phantasie :D, das sind die empfohlenen arbeitsweisen von OS entwicklern.
    statt z.b. einen thread pro socket aufzumachen, nutzt man I/O completion ports, statt einen thread fuer maus und einen fuer keyboard und einen fuer... aufzumachen, nutzt man die windows message pipe, selbst dein arbeitgeber will sicher nicht nur am anfang und am ende deines projektes interaktion und ansonsten in seinem thread leben, sondern zerlegt deine tasks in stuecke die bis 16 manstunden dauern sollten.
    Ob das ueberhaupt immer geht? ja! das geht. aber es kann arbeit sein. im nachinein ist es zuviel arbeit (-> thread loesung wird meist genutzt), wenn du es von anfang an machst, geht das erstaunlich gut.

    Schlimmer noch, man hat eigentlich Calls von einer niederwertigen Schicht in eine viel höhere Schicht rein. Weiterhin setzt es v******, dass man seine Arbeit überhaupt in kleine Pakete teilen kann, um ProcessMessages aufrufen zu können. Nutzt einem wenig, wenn man in einer synchronen Betriebssystemfunktion festhängt.

    du bist natuerlich nicht der erste dem das auffaelt, aus diesem grund hat jedes moderne OS fuer jeden fall die asynchronen versionen und aus reponsivness, performance und skalierungssicht wird immer empfohlen darauf zurueckzugreifen.

    Oder man kann einfach beides in verschiedene Threads packen und nutzt damit die Preemption von seinem OS, kann Layer sauber trennen und muss sich auch keine Gedanken um synchrone OS-Funktionen machen, etc.

    als lazy version ist das natuerlich gaengig, aber es ist halt etwas unkontrollierbares in vielen aspekten. natuerlich kannst du vieles abgeben und damit wirbt man heutzutage auch, du kannst sicherlich auch eine datenbank in lua schreiben und bekommst mit sicherheit eine akzeptable loesung fuer dich. aber wenn jemand dem gegenueber etwas von IBM oder SUN stellt, auch wenn du ehrlich sagen kannst, zu 80% machen die dasselbe, sind es dann die 20% die 10mal mehr zeit kosten weil man sie ordentlich macht und bei der gegenueberstellung machen diese dinge dann den riesen unterschied.

    Ich hoffe das reicht dir als Beispiel.

    hmm, ich denke es kommt wohl drauf an was das ziel ist beim programmieren. wenn man ein kleines tool einfach quick&dirty haben will, sind ein paar threads drauf gut, kann man sich dann auch in einer scriptsprache erstellen und fertig.
    zielt man auf qualitaet, denke ich sollte alles zusammenhaengend gut sein.


  • Mod

    Morle schrieb:

    Ethon schrieb:

    cooky451 schrieb:

    Ethon schrieb:

    Denkst du? Zb asynchrones Lesen von einer Datei heißt ja im Optimalfall dass das OS eine DMA-Aktion startet und den Auftraggeber informiert sobald der Controller seinen ganzen Krempel in den RAM geschrieben hat. Da hat das OS/die CPU ja 0.0 Rechenaufwand dabei.

    Von Rechenaufwand hat niemand gesprochen, nen Thread brauchst du trotzdem dafür.

    Sagen wir es mal so, du brauchst keinen einzigen Thread mehr als wenn das Feature nicht vorhanden wäre.

    Bei einem sychronen Aufruf passiert alles auf deinem Thread. Bei einem asynchronen Aufruf erfolgt der Callback der asynchronen Routine auf einem Kernel-Thread oder aber man schickt dir eine Windows Nachricht. Irgendjemand hat aber diese Nachricht im Kernel auch erzeugen müssen. Da das nicht auf deinem Thread passiert ist, hat das also ein Kernel-Thread getan.

    nein, nicht wirklich, dein user level thread kann kein controller interrupt bekommen. wenn du eine synchrone funktion aufrufst, ruft sie intern eine asynchrone auf und synchronisiert drauf.
    das liegt am treibermodel moderner betriebsysteme, es darf keinen status geben oder 'unknown' ist. also hast du deine daten nocht nicht, oder du hast sie, 'bin am empfangen' gibt es nicht.
    aus diesem grund koennen treiber abstuerzen die deinen request verarbeitet haben, kann eine hotswap festplatte entfernt werden oder auch dein system in sleep gehen, wenn alles laeuft wie geplant merkt deine applikation davon eigentlich nichts. dazu ist es aber noetig dass es diese trennschicht gibt, denn deine festplatte 'redet' nicht mit 20 programmen gleichzeitig und schickt denen auch keine notification, du schichst mit einer OS funktion ein request an windows, windows verteilt die requests dann an die resource verwalter (treiber), die treiber sind dann an ihrer message queue, empfangen die daten und koennen dann machen was sie wollen.
    wenn du z.b. eine teure netzwerkkarte von intel hast, hat die eine CPU drauf und 256MB, die bekommt die requests direkt und meldet sich wieder wenn sie soweit ist per interrupt beim treiber. hast du eine billige soundkarte, dann wird der treiber den ganzen sound transcodieren und mischen etc. vermutlich in einem thread.
    aber es wird nie passieren, dass dein applikation thread mehr macht als dem kernel eine aufgabe zur weiterleitung zu geben. sogar ein memory mapped file auf dem du direkt arbeitest wird keine writes direkt an die HDD schicken, sondern page faults ausloesen bei windows, wodurch windows die page als 'modified' markeirt, irgendwann diese modifizierten dann fuer deine app sperrt, dann in die festplatten-controller-treiber-queue steckt und dann wird es geschrieben.

    Ein DMA Controller oder was auch immer informiert deine *CPU* (nicht OS), über eine Interruptleitung. Dadurch wird eine Interrupt-Service Routine ausgeführt (nach Rapsos Defintion soll das wohl der Interrupt-Thread sein). ISR sind aber eigentlich Threads (zumindest nicht im OS Sinne), denn mit Threads ist ein Kontext assoziiert, mit einer ISR erstmal nicht.

    eine ISR leitet den request an den eigentlichen thread dafuer weiter, ISR sollen ja nur deswegen als proxy dienen, damit kein treiberentwickler dort was kaputmachen kann. sie nehmen daten auf, schicken sie weiter, dazu notifiaction und return. sonst werden interrupts verschluckt. laut meiner definition ist ISR noch der interrupt, der das OS informiert einen interrupt Thread aufzuwecken.

    Es würde mich schwer wundern, wenn dein Asynchroner Callback direkt innerhalb der ISR ausführt werden würde. Damit könntest dein ganzes System zum Stillstand bringen, denn während ein Interrupt verarbeitet wird, kann normalerweise kein anderer verarbeitet werden. Deswegen wird in der ISR der oben genannte Kernel Thread informiert, dass jetzt Daten vorliegen. Der macht dann dein Callback.

    aber widersprichst du damit nicht deiner aussage selbst?"Bei einem sychronen Aufruf passiert alles auf deinem Thread.".
    denn jetzt sagst du, es gibt keine synchronen wege. oder meinst du jetzt der ISR meldet sich direkt beim thread deiner applikation? das passiert nichtmal auf konsolen heutzutage.


  • Mod

    cooky451 schrieb:

    @rapso: Wenn nicht Kommunikation, wo ist dann der Punkt? OS Scheduling? Ich verstehe auch nicht wirklich, wie du das dann zusammenbasteln willst mit einer einzigen queue. Wenn da jetzt 4 rechenintensive Aufgaben drin stehen, und dahinter { process_gui_stuff();

    1. es stehen keine rechenintensiven aufgaben drinnen, wenn du weisst, dass eine aufgabe rechenintensiv werden wuerde, teilst du sie auf.
    2. process_something ist die eine funktion die herrscht. sagen wir mal du hast einen single thread raytracer, der eine UI mit einem cancel button hat und dazu per netzwerk 100 slaves die tracen.

    die thread loesung:
    -thread fuer deinen tracer
    -thread fuer deine UI
    -100threads fuer deine slaves

    fall 1: user klickt 'cancel', dein tracing thread, der einen tag arbeitet an seinem teil muss also alle t mal auf die variable schauen, die der UI thread bekommen hat. er muss alle zeit auch mal eine funktion aufrufen, die das bild aktualisiert wie es nun ausschaut, damit der UI thread das zeigen darf. wenn du das alle t ms machst, braucht ein click vom user t ms bis dein program reagiert. wenn der user das bild refresht wie verrueckt, braucht es t ms bis er etwas neues sieht.
    fall 2: 100threads verlangen dynamisch nach neuen arbeitspacketen, deren leistung ist unterschiedlich, jedes arbeitspacket ist unterschiedlich aufwendig, halt sehr flexibel. also stecken diese 100threads in eine queue oder variable oder wie auch immer eine benachrichtigung (oder in 100queues?), wenn sie ein netzwerkpacket erhalten haben, dein thread checkt diese alle 100s und liest die neuen daten ein, verarbeitet diese und erstellt neue arbeitspackete aufgrund der neuen daten.

    die single-thread event-queue loesung:
    -du nutzt der einfachheit halber die windows message queue, diese beinhaltet sowohl den user input als auch socket events.

    dein loop sieht in etwa so aus

    while(true)
    {
      while(peekmessage(msg))
        process(msg);
      if(IsRunning())
      {
        tracejob();
        UpdateImage();
      }
    }
    

    (das ist keine loesung um alle thread loesungen zu ersetzen, sondern nur ein beispiel fuer diesen speziellen fall!)

    fall 1. statt von deinem thread, nimmt sich das program die message direkt von windows.
    fall 2. statt von den 100threads, nimmt sich das program die message ..

    ich sehe keine bessere responsiveness durch threads, sowohl bei user input als auch bei netzwerk zugriff auf den scheduler. der user interagiert mit der UI mit einem grund, er will 1. es abbrechen 2. aktualisieren, obwohl im thread modus beide buttons scheinbar sofort reagieren (weil sie sich animieren), bricht das program weder ab, noch aktualisiert sich etwas.

    es verbirgt eher durch die suggerierung einer aktion, dass nichts passiert. im zweiten fall, da wird sich der programmierer einfallen lassen muessen wie er 'tracejob' feiner macht, damit es feedback gibt. wenn ein user beide programme taeglich bedient, ich denke nicht, dass die thread loesung ihm besser gefaellt.

    }, hängt doch alles nur noch? Sicher, die Aufgaben werden 1 ms schneller fertig, aber das ist es doch wohl kaum Wert, wenn der User während der Zeit nichts machen kann. Wenn der GUI Thread durchgängig bei GetMessage() hängt und nur nach "hinten" durchleitet, sollte das wohl kaum Probleme geben. Ja, man verlässt sich auf das OS, aber dafür ist es doch da. Ich versuche wirklich zu sehen wo jetzt das Problem ist, aber ich verstehe es einfach nicht.

    es geht mir darum dass es erstmal nichts bringt. natuerlich kann der user dann das fenster resizen oder menues aufmachen die ausgegraut sind weil "waehrend des compiliervorgangs koennen sie nicht speichern" oder sowas, aber das ist nicht was responsivitaet ist, sondern nur eine illusion davon.
    wenn du willst dass die UI responsiv ist, musst du auch die dahinterstehenden strukturen/algorithmen etc. responsiv machen, und wenn du das machst, dann wirst du keinen thread mehr brauchen, wozu auch?


  • Mod

    ich glaube fast wir sollten uns dafuer eher im pub treffen 🤡, das sind ja gebete dich ich da tippe 😮



  • Nenenene, 1 GUI Thread, 1 Background Thread. Nix 100 Threads für jeden Clienten. Wenn der Background-Thread etwa alle 15ms checkt was läuft (<.<), dürfte der eine atomic access so gut wie keinen Einfluss auf die Performance haben. Wenn der User also abbrechen klickt, ist nach durchschnittlich 7.5, spätestens nach 15 ms alles abgebrochen. Das ist für den User so gut wie instant.

    rapso schrieb:

    es stehen keine rechenintensiven aufgaben drinnen, wenn du weisst, dass eine aufgabe rechenintensiv werden wuerde, teilst du sie auf.

    Also wenn ich eine Matrix Lösen will dann teile ich das in 1000 kleine Aufgaben ein und jage alles durch einen großen Scheduler damit zwischendurch auch mal der GUI Kram dran kommt? Das halte ich 1. für wesentlich umständlicher, 2. für wesentlich unperformanter und 3. löst es das Problem nicht, wenn 100 dieser Päckchen hintereinander stehen, muss ein GUI Paket immer noch ewig warten. Nein, man braucht einfach getrennte queues.

    rapso schrieb:

    ich glaube fast wir sollten uns dafuer eher im pub treffen 🤡, das sind ja gebete dich ich da tippe 😮

    Hehe ich fürchte nur die Fahrtzeit von Aachen aus macht das wieder ineffektiv. 🤡

    Am schönsten wäre natürlich, wenn man von "außen" in einem Thread eine Exception auslösen könnte, dann müssten die Algorithmen selbst nicht mal mehr die Checks einbauen. Aber sowas gibt's wohl noch nicht. Und man müsste auch irgendwie sicherstellen, dass der andere Thread nicht gerade dabei ist eine Ressource zu reservieren, alles nicht so leicht. Aber eine vollständige Entkopplung von Thread Zeug und Algorithmus wäre wirklich toll.



  • cooky451 schrieb:

    Ethon schrieb:

    Denkst du? Zb asynchrones Lesen von einer Datei heißt ja im Optimalfall dass das OS eine DMA-Aktion startet und den Auftraggeber informiert sobald der Controller seinen ganzen Krempel in den RAM geschrieben hat. Da hat das OS/die CPU ja 0.0 Rechenaufwand dabei.

    Von Rechenaufwand hat niemand gesprochen, nen Thread brauchst du trotzdem dafür.

    Nein, brauchst du nicht.



  • cooky451 schrieb:

    und 3. löst es das Problem nicht, wenn 100 dieser Päckchen hintereinander stehen, muss ein GUI Paket immer noch ewig warten. Nein, man braucht einfach getrennte queues.

    Für sowas gibt's priority-queues.



  • Schon klar, aber welchen Vorteil hat das? (Gegenüber Threads) Es wird nur noch komplizierter (und ineffizienter) - GUI hat keine bestimmte Priorität, sie soll einfach in festen Intervallen gecheckt werden, und das ist ziemlich genau das, was der OS Scheduler macht.


Anmelden zum Antworten