Sind Go-langs-Goroutine-Pools nur grüne Fäden?

47

Der Kommentator hier kritisiert folgende grüne Fäden:

Ich wurde anfangs mit dem N: M-Modell verkauft, um ereignisgesteuertes Programmieren ohne die Rückruf-Hölle zu ermöglichen. Sie können Code schreiben, der wie schmerzhafter alter Prozedurcode aussieht, aber darunter verbirgt sich Magie, die das Wechseln von Benutzerbereichsaufgaben verwendet, wenn etwas blockieren würde. Klingt gut. Das Problem ist, dass wir Komplexität mit mehr Komplexität lösen. swapcontext () und family sind ziemlich eng, die Komplexität kommt von anderen ungewollten Stellen.

Plötzlich sind Sie gezwungen, einen Userspace-Scheduler zu schreiben und zu erraten, was es wirklich schwierig macht, einen Scheduler zu schreiben, der bessere Arbeit leistet als die Linux-Zeitpläne, für die jahrelange Anstrengungen erforderlich sind. Jetzt möchten Sie, dass Ihr Zeitplan N grüne Threads mit M physischen Threads verknüpft, sodass Sie sich um die Synchronisierung kümmern müssen. Die Synchronisierung bringt Leistungsprobleme mit sich, sodass Sie sofort loslegen können. Es ist keine leichte Aufgabe, einen korrekten Zeitplan mit hoher Gleichzeitigkeit zu erstellen.

Eine andere Kritik ist hier :

Ein einzelner Prozess, der mehrere Threads fälscht, hat viele Probleme. Eine davon ist, dass alle gefälschten Threads bei einem Seitenfehler blockieren.

Meine Frage ist - sind Go-Langs Goroutinen (für einen Standardpool) nur grüne Fäden? Wenn ja - gehen sie auf die obigen Kritikpunkte ein?

Falkenauge
quelle

Antworten:

67

Ich bin nur ein gelegentlicher Go-Benutzer, nehmen Sie also Folgendes mit einem Körnchen Salz.

Wikipedia definiert grüne Threads als "Threads, die von einer virtuellen Maschine (VM) anstatt vom zugrunde liegenden Betriebssystem geplant werden". Grüne Threads emulieren Multithread-Umgebungen, ohne auf native Betriebssystemfunktionen angewiesen zu sein. Sie werden im Benutzerbereich statt im Kernel-Bereich verwaltet, sodass sie in Umgebungen ohne native Thread-Unterstützung arbeiten können.

Go (oder genauer gesagt die beiden vorhandenen Implementierungen) ist eine Sprache, die nur nativen Code erzeugt - es wird keine VM verwendet. Darüber hinaus stützt sich der Scheduler in den aktuellen Laufzeitimplementierungen auf Threads auf Betriebssystemebene (auch wenn GOMAXPROCS = 1 ist). Ich halte es daher für etwas missbräuchlich, über grüne Fäden für das Go-Modell zu sprechen.

Go-Leute haben den Begriff Goroutine geprägt, um Verwechslungen mit anderen Nebenläufigkeitsmechanismen (wie Coroutinen oder Threads oder Lightweight-Prozesse) zu vermeiden.

Natürlich unterstützt Go ein M: N-Threading-Modell, das dem Erlang-Prozessmodell jedoch viel näher kommt als dem Java-Green-Thread-Modell.

Hier sind einige Vorteile des Go-Modells gegenüber Green Threads (wie in früheren JVM-Versionen implementiert):

  • Mehrere Kerne oder CPUs können auf transparente Weise für den Entwickler effektiv genutzt werden. Bei Go sollte sich der Entwickler um die Parallelität kümmern. Die Go-Laufzeit sorgt für Parallelität. Java-Green-Threads-Implementierungen wurden nicht über mehrere Kerne oder CPUs skaliert.

  • System- und C-Aufrufe sind für den Scheduler nicht blockierend (alle Systemaufrufe, nicht nur diejenigen, die Multiplex-E / A in Ereignisschleifen unterstützen). Green-Threads-Implementierungen können den gesamten Prozess blockieren, wenn ein Systemaufruf blockiert wurde.

  • Kopieren oder segmentierte Stapel. In Go muss keine maximale Stapelgröße für die Goroutine angegeben werden. Der Stapel wächst schrittweise nach Bedarf. Eine Konsequenz ist, dass eine Goroutine nicht viel Speicher benötigt (4KB-8KB), so dass eine große Anzahl von ihnen glücklich erzeugt werden kann. Goroutine-Nutzung kann daher allgegenwärtig sein.

Um auf die Kritik einzugehen:

  • Mit Go müssen Sie keinen Userspace-Scheduler schreiben, der bereits mit der Laufzeit ausgeliefert wird. Es ist eine komplexe Software, aber es ist das Problem der Go-Entwickler, nicht der Go-Benutzer. Die Verwendung ist für Go-Benutzer transparent. Unter den Go-Entwicklern ist Dmitri Vyukov ein Experte für sperrenfreie / wartefreie Programmierung, und er scheint besonders daran interessiert zu sein, die möglichen Leistungsprobleme des Schedulers zu lösen. Die aktuelle Scheduler-Implementierung ist nicht perfekt, wird sich aber verbessern.

  • Die Synchronisierung bringt Leistungsprobleme und Komplexität mit sich. Dies gilt zum Teil auch für Go. Beachten Sie jedoch, dass das Go-Modell versucht, die Verwendung von Kanälen und eine saubere Zerlegung des Programms in gleichzeitigen Goroutinen zu fördern, um die Komplexität der Synchronisation zu begrenzen (dh Daten durch Kommunikation zu teilen, anstatt Speicher für die Kommunikation zu teilen). Übrigens bietet die Referenz-Go-Implementierung eine Reihe von Tools zur Behebung von Leistungs- und Nebenläufigkeitsproblemen, z. B. einen Profiler und einen Race Detector .

  • In Bezug auf Seitenfehler und das Fälschen mehrerer Threads beachten Sie bitte, dass Go Goroutine über mehrere System-Threads hinweg planen kann. Wenn ein Thread aus irgendeinem Grund blockiert wird (Seitenfehler, Blockieren von Systemaufrufen), verhindert dies nicht, dass die anderen Threads weiterhin andere Goroutinen planen und ausführen. Nun ist es wahr, dass ein Seitenfehler den Betriebssystem-Thread blockiert, mit allen Goroutinen, die für diesen Thread geplant werden sollen. In der Praxis sollte der Go-Heap-Speicher jedoch nicht ausgetauscht werden. Dies wäre auch in Java der Fall: Garbage Collected Languages ​​nehmen den virtuellen Speicher ohnehin nicht sehr gut auf. Wenn Ihr Programm mit Seitenfehlern auf angemessene Weise umgehen muss, wenn dies wahrscheinlich daran liegt, dass ein Teil des Off-Heap-Speichers verwaltet werden muss. In diesem Fall,

Goroutinen sind also keine grünen Fäden, und die Go-Sprache und die derzeitige Implementierung richten sich hauptsächlich gegen diese Kritik.

Didier Spezia
quelle
1
Eine ausgezeichnete und detaillierte Antwort auf die Frage :)
Tuxdude
1
Ich liebe diese Antwort, aber haben Sie Hinweise darauf, wie / wann die OS-Threads erstellt werden?
Lars
1
Einer der größten Nachteile von Go Language ist, dass es für jeden blockierenden Systemaufruf einen Kernel-Thread erstellt!
user1870400
8
Beachten Sie, dass der Artikel "Grüner Thread" in Wikipedia geändert wurde und "Threads, die von einer Laufzeitbibliothek oder einer virtuellen Maschine (VM) geplant werden" enthält. Dies bedeutet, dass Ihre Antwort nach dieser Definition nicht mehr korrekt ist, da die Go-Laufzeit die Planung / Verwaltung übernimmt. Ich denke, es ist hilfreicher, grüne Threads als User-Space-Threads zu definieren, die OS-Threads gegenüberstellen. Und dann, ja, Goroutinen sind mit Sicherheit grüne Fäden.
mknecht
1
2. dass @mknecht. Es geht nicht um die VM, sondern um die Laufzeit. Und Go hat definitiv eine Laufzeit. (verwaltet das Threading-Modell und die Garbage Collection).
Tim Harper