Prinzipielle Frage über Coroutinen



  • Jodocus schrieb:

    Wäre es nicht besser, der Kernel würde an sich Threads anbieten, die nur einen "Kontextwechsel light" durchführen, anstatt "Staat im Staat"-mäßig das den Anwendungen zu überlassen?

    Du willst Syscalls haben, die dir die Latenz von Syscalls eliminieren?



  • dachschaden schrieb:

    Jodocus schrieb:

    Wäre es nicht besser, der Kernel würde an sich Threads anbieten, die nur einen "Kontextwechsel light" durchführen, anstatt "Staat im Staat"-mäßig das den Anwendungen zu überlassen?

    Du willst Syscalls haben, die dir die Latenz von Syscalls eliminieren?

    Dass der Übergang zum Kernel-Mode auf aktuellen Systemen teuer ist (z.B. per SYSENTER), wage ich mal zu bezweifeln. Das stärkere Argument war ja, dass Green Threads keinen vollständigen (da unnötigen) Kontextwechsel durchführen. Das scheint ein sinnvoller Ansatz zu sein, wenn man es auf viele Kontextwechsel ankommen lassen will. Der Ansatz, möglicht wenig Kontextwechsel zu haben, die dafür dann komplette Kontextwechsel sind, könnte man eigentlich gut durch Green Threads ergänzen, um das beste aus beiden Welten zu haben. Daher halte ich Sachen wie Green Threads für weniger als Sprachfeature sondern mehr als Kernel-Feature geeignet. Sachen wie Scheduling gehören imho nicht in Applikationen außerhalb des Kernels.



  • Jodocus schrieb:

    Das würde also bedeuten, man müsste auch Green Mutexe basteln, die nicht den ganzen Thread blockieren, sondern den nächsten Aufrufen - man müsste also alle Datenstrukturen entsprechend umbauen.

    Ja, die braucht man. In Go gibt es dafür die Channel, in Haskell gibt es MVar etc. und der jeweilige Scheduler in der Runtime kann damit umgehen und schedult z.B. keine Threads, die gerade durch einen Mutex gelockt sind. Also im Prinzip so, wie es der Kernel auch macht.

    Du hast natürlich recht, es wäre schön, wenn der Kernel bzw. das OS sowas von sich aus schon anbieten würde. Unter Windows gibt es ja dafür die Fiber, die man nutzen kann, um ein solches System zu bauen. Natürlich ist es trotzdem noch relativ aufwendig. Unter Linux ist mir nichts vergleichbares bekannt.

    Aber auf der anderen Seite, natürlich sind die Kernel-Entwickler sehr kompetent, aber auch nicht heilig. Es gibt prinzipiell keinen Grund, warum die Usermode-Scheduler schlechter als der des Kernels sein sollten. Und es handelt sich hierbei um ein Problem, welches sich komplett innerhalb der Anwendung abspielt und was mit dem restlichen System überhaupt nichts zu tun hat. Warum sollte man das dem Kernel überlassen?

    Die Implementierung ist halt leider relativ aufwendig, insbesondere wenn die Sprache recht low-level ist und eigentlich nicht darauf ausgelegt wurde. Aber es scheint tatsächlich auch für C ein paar Bibliotheken zu geben, siehe z.B. diese SO-Frage.



  • Unter Windows sind Fibers ja leider auch nur rein kooperativ. Natürlich muss ein UM-Scheduler nicht schlechter sein als einer im Kernel-Mode, aber unter dem Gesichtspunkt kommt es mir dann schon so wie die Mutter aller premature optimizations vor, wenn einem der Scheduler nicht passt. 😉

    Danke für die Klarstellungen/Anregungen.



  • Jodocus schrieb:

    Dass der Übergang zum Kernel-Mode auf aktuellen Systemen teuer ist (z.B. per SYSENTER), wage ich mal zu bezweifeln.

    Seit Version 2.3.4 der Glibc speichern sie den Return von getpid , weil sie ansonsten den Kernel davon anhauen müssten. Weil der Wechsel in Kernelmode nun mal teuer ist. Auch heute noch. Aber nicht so teuer, dass ich das bei Threads jemals bemerkt hätte.

    Ich sag's direkt, mit Userland-Threads (a.k.a Green Threads) habe ich noch nicht gearbeitet, weil meiner (persönlichen) Erfahrung nach die Kontextwechsel nie das Problem waren. Was das Problem war, ist dass Windows dich den zu verwendenden Stackspeicher nicht auswählen lässt und pthreads, wenn du den Stackspeicher nicht selbst setzt, auch stark unterdurchschnittlich performt.

    Sobald ich diesen Flaschenhals dann mal eliminiert habe, habe ich mit pthreads (meines Wissens nach Kernel-Threads) einen Load Average von > 3000 erzeugt, und das System hat noch reagiert. Verzögert, aber es war da.

    EDIT: Auf Linux natürlich. Windows lässt dich den Thread-Speicher auch mit pthreads (gibt ja Windows-Implementierungen) nicht auswählen.



  • Ich hab bisher ein mal coroutines verwendet. Ich hatte eine öffentliche Iterator Schnittstelle, intern aber eine rekursive Suche. Sobald die rekursive Funktion was interessantes gefunden hat, hat sie dann quasi yield aufgerufen.
    War im Endeffekt Spielerei, weil ich mal coroutines verwenden wollte 😉 An der Stelle hätte ich einfach alles durchsuchen und dann über die Ergebnisse iterieren können.



  • Ich hatte Fibers(Windows-Leichtgewichtige-Threads-Nur-Kooperativ) verwendet, als WinXP bei 3400 Threads (mit je supi sparsam stack und beliebig viel damals einbaubarem RAM) abgekackt ist und kam nicht echt weiter. Fibers sind nicht besser als Threads und die sind, behaupte ich mal, in fast allen bezahlten Anwendungen nicht besser als Prozesse.

    Ich will zwei 22-Kerner auf Dual-Board mit Hyperthreading haben, was 88 Threads macht und die Compilerfehlermeldung kommt gefühlt in die IDE lange bevor ich die Compile-Taste gedrückt habe.



  • volkard schrieb:

    [Threads] sind, behaupte ich mal, in fast allen bezahlten Anwendungen nicht besser als Prozesse.

    • Datenaustausch zwischen Threads eines Prozesses geht richtig schnell.
    • belegen keine doppelten COW-Einträge in der Page Table (ist egal, ob die COW oder RO sind, Hauptsache ist, sie existieren und können somit zu Page Walks führen).
    • sind wesentlich schneller zu erstellen (ein Benchmark von mir aus dem Jahr 2013 auf Linux zeigte, dass Threads so um den Fatkor 50 schneller erstellt werden als zu forken).
    • (auf Linux) kannst du deinen eigenen Speicher als Threadstack angeben, was noch mal die Leistung hochbringt.

    Gegenargumente?



  • Ähhhh, Quatsch, Faktor 25. Forken war 50 Zeiteinheiten, Thread erstellen zwei.



  • dachschaden_off schrieb:

    volkard schrieb:

    [Threads] sind, behaupte ich mal, in fast allen bezahlten Anwendungen nicht besser als Prozesse.

    • Datenaustausch zwischen Threads eines Prozesses geht richtig schnell.
    • belegen keine doppelten COW-Einträge in der Page Table (ist egal, ob die COW oder RO sind, Hauptsache ist, sie existieren und können somit zu Page Walks führen).
    • sind wesentlich schneller zu erstellen (ein Benchmark von mir aus dem Jahr 2013 auf Linux zeigte, dass Threads so um den Fatkor 50 schneller erstellt werden als zu forken).
    • (auf Linux) kannst du deinen eigenen Speicher als Threadstack angeben, was noch mal die Leistung hochbringt.

    Gegenargumente?

    [Threads] sind, behaupte ich mal, in fast allen bezahlten Anwendungen nicht besser als Prozesse.
    Mir geht es nicht um theoretische Mikromessungen oder Gamecoding, sondern das, wo der Kunde fett Geld bezahlt für die Software.
    Die Mikroargumente kenne ich alle, klar, ich bin auch ein Fan davon, dem Thread 64k eigenen Stackspeicher unterzuschubsen, und dann auch gleich noch innerhalb des Threads davon 32k abzuwacken und ein selbergeschriebenes malloc/free darauf aufsetzten.


Anmelden zum Antworten