Reihenfolge der Gorroutine Entsperrung auf einem einzelnen Kanal

8

Sorgt die Reihenfolge, in der die Goroutinen auf einem Kanal blockieren, für die Reihenfolge, in der sie die Blockierung aufheben? Ich bin nicht besorgt über die Reihenfolge der Nachrichten, die gesendet werden (sie sind garantiert bestellt), aber die Reihenfolge der Goroutines, die entsperren wird.

Stellen Sie sich einen leeren Kanal ch zwischen mehreren Goroutinen vor (1, 2 und 3), wobei jede Goroutine versucht, eine Nachricht auf ch zu erhalten. Da ch leer ist, wird jede Goroutine blockiert. Wenn ich eine Nachricht an ch sende, wird Gorroutine 1 zuerst entsperren? Oder könnten 2 oder 3 möglicherweise die erste Nachricht erhalten? (Oder umgekehrt, mit den Goroutines versuchen zu senden)

Ich habe einen Spielplatz , der darauf hinweist, dass die Reihenfolge, in der Goroutine blockiert, die Reihenfolge ist, in der sie entsperrt werden , aber ich bin nicht sicher, ob dies ein undefiniertes Verhalten wegen der Implementierung ist.

    
Justin 16.09.2014, 04:27
quelle

3 Antworten

3

Dies ist eine gute Frage - sie berührt einige wichtige Probleme beim simultanen Design. Wie bereits erwähnt, ist die Antwort auf Ihre spezifische Frage, gemäß der aktuellen Implementierung, FIFO basiert. Es ist unwahrscheinlich, dass es jemals anders sein wird, außer vielleicht, wenn die Implementierer entschieden haben, dass ein LIFO aus irgendeinem Grund besser ist.

Es gibt jedoch keine Garantie . Sie sollten also vermeiden, Code zu erstellen, auf den bei einer bestimmten Implementierung angewiesen ist.

Die umfassendere Frage betrifft Nicht-Determinismus , Fairness und Hunger .

Vielleicht überraschend, Nicht-Determinismus in einem CSP-basierten System kommt nicht von Dingen, die parallel geschehen. Es ist möglich wegen Parallelität, aber nicht wegen der Parallelität. Stattdessen entsteht Nicht-Determinismus, wenn eine Entscheidung getroffen wird . In der formalen Algebra von CSP wird dies mathematisch modelliert. Glücklicherweise müssen Sie die Mathematik nicht kennen, um Go verwenden zu können. Aber formal werden zwei goroutines-Codes parallel ausgeführt und das Ergebnis könnte immer noch deterministisch sein, vorausgesetzt, dass alle Auswahlmöglichkeiten eliminiert sind.

Go erlaubt Auswahlmöglichkeiten, die Nicht-Determinismus explizit über select einführen und implizit über die Enden der Kanäle, die zwischen den Gououtines geteilt werden. Wenn Sie Punkt-zu-Punkt-Kanäle (ein Leser, ein Schreiber) haben, entsteht die zweite Art nicht. Wenn es in einer bestimmten Situation wichtig ist, haben Sie eine Designauswahl, die Sie treffen können.

Fairness und verhungern sind typischerweise gegensätzliche Seiten derselben Medaille. Starvation ist eines dieser dynamischen Probleme (zusammen mit Deadlock, Livelock und Race Conditions), die möglicherweise zu einer schlechten Leistung, wahrscheinlicher zu falschem Verhalten führen. Diese dynamischen Probleme sind nicht testbar (mehr dazu ) und benötigen einige Level-Analysen, um sie zu lösen. Wenn ein Teil eines Systems nicht reagiert, weil es keinen Zugang zu bestimmten Ressourcen hat, dann ist es offensichtlich notwendig, diese Ressourcen besser zu verwalten.

Der gemeinsame Zugang zu den Kanalenden kann aufgrund des aktuellen FIFO-Verhaltens durchaus ein gewisses Maß an Fairness bieten und dies mag ausreichend erscheinen. Aber wenn Sie es (unabhängig von Implementierungsunsicherheiten) garantiert haben möchten, können Sie stattdessen ein select und ein Bündel von Punkt-zu-Punkt-Kanälen in einem Array verwenden. Fair Indexing ist einfach zu erreichen, indem man sie immer in einer Reihenfolge vorzieht, in der die zuletzt ausgewählten am unteren Rand des Stapels platziert werden. Diese Lösung kann Fairness garantieren, aber wahrscheinlich mit einer kleinen Leistungseinbuße.

(beiseite: siehe "Wot No Chickens" für eine etwas amüsante Entdeckung, die von Forschern in Canterbury, Großbritannien, bezüglich eines Fairness-Fehlers in der Java Virtual Machine gemacht wurde - der nie korrigiert wurde!

    
Rick-777 16.09.2014, 22:20
quelle
2

Ich glaube, es ist nicht spezifiziert, weil das Speichermodelldokument nur sagt: "Ein Sendevorgang auf einem Kanal findet vor dem entsprechenden Empfang von diesem Kanal statt schließt ab. " Die Spec-Abschnitte zu senden Statements und der Empfangsoperator sagt nichts darüber, was zuerst freigeschaltet wird. Im Moment verwendet die GC Toolchain eine geordnete FIFO-Warteschlange, um zu kontrollieren, welche Goroutine die Blockierung aufhebt, aber ich tue nicht. Ich sehe keine Versprechen in der Spezifikation, dass es immer so sein muss.

(Nur für den allgemeinen Hintergrund ist zu beachten, dass der Playground-Code mit GOMAXPROCS = 1 läuft, d. h. mit einem Kern, so dass einige Arten von Nebenläufigkeits-Unvorhersehbarkeit einfach nicht auftreten.)

    
twotwotwo 16.09.2014 04:35
quelle
0

Die Reihenfolge wurde nicht angegeben, aber die aktuellen Implementierungen verwenden eine FIFO-Warteschlange für wartende Gatroutinen.

Das maßgebliche Dokument ist das Go Memory-Modell . Das Speichermodell definiert keine "Vor-Vor" -Beziehung für zwei auf denselben Kanal gesendete Gououtines, daher wird die Reihenfolge nicht angegeben. Dito für den Empfang.

    
Simon Fox 16.09.2014 06:21
quelle

Tags und Links