Ist die Weiterleitung von Nachrichten über Kanäle in der Warteschlange garantiert nicht blockierend?

8

Um zu beurteilen, ob go eine mögliche Option für eine Audio- / Videoanwendung ist, würde ich gerne wissen, ob die Nachrichtenübergabe alle nicht blockierenden Fortschrittsgarantien erfüllt (ob blockierungsfrei, blockierungsfrei oder wartefrei) ). Insbesondere sind die folgenden Szenarien relevant:

Einzelproduzent Einzelverbraucher:

Zwei Threads kommunizieren über einen gemeinsamen Kanal. Thread A führt nur asynchrone Nachrichten aus, Thread B nur asynchrone Nachrichten. Angenommen, der OS-Scheduler entscheidet, den Thread A für einen unbestimmten Zeitraum zum "schlimmsten möglichen Zeitpunkt" zu unterbrechen. Ist Thread B garantiert, eine Empfangsoperation in einer beschränkten Anzahl von CPU-Zyklen zu beenden, oder gibt es eine (theoretische) Möglichkeit, dass Thread A den Kanal in einen Zustand versetzen kann, in dem Thread B warten muss, bis das OS Thread A wieder aufnimmt? p>

Mehrere Hersteller:

Mehrere Threads A1, A2, A3, ... kommunizieren mit einem oder mehreren anderen Threads unter Verwendung eines gemeinsamen Kanals. Die Threads Ai tun nur asynchrone Sends. Angenommen, A2, A3, ... werden vom OS-Scheduler für einen unbestimmten Zeitraum zum "schlimmsten möglichen Zeitpunkt" ausgesetzt. Ist Thread A1 immer noch garantiert, einen Sendevorgang in einer begrenzten Anzahl von CPU-Zyklen zu beenden? Angenommen, jeder Thread möchte nur einen senden. Wenn das Programm ausreichend lange ausgeführt wird (mit einem "böswilligen" Scheduler, der potenziell Threads oder Interrupts verhungern lässt und Threads zum "schlimmsten möglichen Zeitpunkt" wieder aufnimmt), ist mindestens ein Sendevorgang garantiert erfolgreich?

Ich bin nicht so sehr an typischen Szenarien interessiert, sondern an Worst-Case-Garantien. Siehe Blockierungsalgorithmus (Wikipedia) für weitere Details zu Obstruktions-, Sperr- und Warte-Algorithmen

    
Tobias 17.07.2011, 19:18
quelle

4 Antworten

4

Das Go-Speichermodell erfordert nicht, dass die gesendeten und empfangenen Daten blockierungsfrei sind, und der aktuelle Laufzeit Implementierung sperrt den Kanal für send und recv . Dies bedeutet zum Beispiel, dass es möglich ist, eine sendende oder empfangende Go-Routine zu verhungern, wenn der OS-Scheduler einen anderen Thread unterbricht, der eine andere Go-Routine ausführt, die versucht, auf dem gleichen Kanal zu senden oder zu empfangen, während er die Sperre des Kanals bereits erlangt hat .

Die Antwort ist leider nein : (

(es sei denn, jemand implementiert Teile der Laufzeit mit nicht blockierenden Algorithmen).

    
Tobias 15.04.2012, 23:18
quelle
9

Normale Sende- und Empfangsoperationen blockieren per Definition. Sie können ein nicht blockierendes Senden oder Empfangen mithilfe einer SELECT-Anweisung durchführen:

%Vor%

(Empfangen ist sehr ähnlich; ersetzen Sie einfach die case-Anweisung.)

Der Sendevorgang findet nur statt, wenn im Puffer des Kanals Platz ist. Andernfalls wird der Standardfall ausgeführt. Beachten Sie, dass intern immer noch ein Mutex verwendet wird (wenn ich den Code richtig lese).

    
Evan Shaw 17.07.2011 20:45
quelle
1

Sie fragen, ob eine Operation innerhalb einer begrenzten Anzahl von Zyklen abgeschlossen werden kann, was natürlich keine Designüberlegung für diese Sprache (oder die meisten zugrunde liegenden Betriebssysteme) ist.

Wenn Go in einem einzigen Thread ausgeführt wird, verwendet Go kooperatives Multitasking zwischen den Goroutines. Wenn also eine Routine niemals nachgibt, wird die andere niemals laufen. Wenn Ihr Programm auf mehreren Threads ausgeführt wird (wie in GOMAXPROCS festgelegt), können Sie mehrere goroutines gleichzeitig ausführen. In diesem Fall steuert das Betriebssystem die Zeitplanung zwischen den Threads. In beiden Fällen gibt es jedoch keine garantierte Obergrenze für die Zeit bis zum Abschluss eines Funktionsaufrufs.

Beachten Sie, dass die kooperative Natur von goroutines Ihnen ein gewisses Maß an Kontrolle über die Ausführung von Zeitplänen gibt - das heißt, Routinen werden niemals vorweggenommen. Bis Sie nachgeben, behalten Sie die Kontrolle über den Thread.

Informationen zum Sperrverhalten finden Sie unter Sprachspezifikation :

  

Die Kapazität in Anzahl der Elemente legt die Größe des Puffers im Kanal fest. Wenn die Kapazität größer als Null ist, ist der Kanal asynchron: Kommunikationsvorgänge sind ohne Blockierung erfolgreich, wenn der Puffer nicht voll ist (senden) oder nicht leer (empfangen) und Elemente in der Reihenfolge empfangen werden, in der sie gesendet werden. Wenn die Kapazität Null oder nicht vorhanden ist, ist die Kommunikation nur erfolgreich, wenn sowohl ein Sender als auch ein Empfänger bereit sind.

Beachten Sie, dass blockierungsfreie Sende- und Empfangsvorgänge für Kanäle mit der bereits erwähnten select -Syntax durchgeführt werden können.

    
tylerl 18.07.2011 17:40
quelle
0

Goroutinen besitzen keine Kanäle oder die Werte, die an sie gesendet werden. Der Ausführungsstatus einer Goroutine, die Werte auf einem Kanal gesendet hat / sendet, hat keinen Einfluss auf die Fähigkeit anderer Gruoutinen, Werte auf diesem Kanal zu senden oder zu empfangen, es sei denn, der Puffer des Kanals ist voll. In diesem Fall werden alle Sends blockiert bis ein entsprechender Empfang erfolgt, oder der Puffer ist leer, in diesem Fall werden alle empfangenen blockiert, bis es einen entsprechenden Sendevorgang gibt.

Da Gaborutinen eine kooperative Planung verwenden (sie müssen dem Scheduler entweder durch eine Kanaloperation, einen Syscall oder einen expliziten Aufruf von runtime.Gosched() nachgeben), ist es unmöglich, dass eine Goroutine bei dem "schlimmstmöglichen" unterbrochen wird Zeit". Es ist möglich, dass eine Goroutine niemals nachgibt, in diesem Fall könnte sie einen Thread auf unbestimmte Zeit binden. Wenn Sie nur einen Thread zur Ausführung haben, werden Ihre anderen Goroutines niemals geplant. Es ist möglich, aber statistisch unwahrscheinlich, dass eine Goroutine niemals geplant wird. Wenn jedoch alle goroutines bis auf eine beim Senden oder Empfangen blockiert sind, muss die verbleibende goroutine eingeplant werden.

Es ist möglich, einen Deadlock zu bekommen. Wenn ich zwei Goroutinen ausführe:

%Vor%

Dann, wie offensichtlich sein sollte, warten beide Goroutinen darauf, dass der andere einen Wert sendet, was niemals passieren wird.

    
SteveMcQwark 20.07.2011 03:37
quelle

Tags und Links