2016-02-24 11 views
5

Ich bin neugierig, warum das Folgende nicht funktioniert. Im Allgemeinen select mit einem default: verhindert Deadlock, aber nicht in diesem Fall:Wählen Sie mit Kanal <- <- Kanal

package main 

import "fmt" 

func main() { 
    a := make(chan int) 
    b := make(chan int) 

    select { 
    case a <- <- b: 
     fmt.Println("this is impossible") 
    default: 
     fmt.Println("select worked as naively expected") 
    } 
} 

Natürlich ist es nicht die <- <- mag aber ich frage mich, was sich hinter der Oberfläche los ist hier. In anderen Situationen ist <- <- erlaubt (obwohl vielleicht nicht empfohlen).

Antwort

6

a <- <- b ist die gleiche wie a<- (<-b), weil die <- Operator assoziiert mit der linken chan möglich.

So hat die select eine case mit einem Sendevorgang (in Form von a<- (something)). Und was passiert hier ist, dass der rechte Ausdruck der send-Anweisung (der zu sendende Wert) zuerst ausgewertet wird - das ist <-b. Aber dies wird blockiert immer (weil niemand etwas auf b Senden ist), so:

fatal error: all goroutines are asleep - deadlock!

Relevante Abschnitt bilden die Spec: Select statements:

Execution of a "select" statement proceeds in several steps:

  1. For all the cases in the statement, the channel operands of receive operations and the channel and right-hand-side expressions of send statements are evaluated exactly once, in source order, upon entering the "select" statement. The result is a set of channels to receive from or send to, and the corresponding values to send. Any side effects in that evaluation will occur irrespective of which (if any) communication operation is selected to proceed. Expressions on the left-hand side of a RecvStmt with a short variable declaration or assignment are not yet evaluated.

  2. If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection. Otherwise, if there is a default case, that case is chosen. If there is no default case, the "select" statement blocks until at least one of the communications can proceed.

  3. ...

Also, wenn default vorhanden ist, die select tut verhindern blockiert, wenn keine der Kommunikation kann in Schritt 2 fortfahren, aber Ihr Code bleibt stecken in Schritt 1.


nur vollständig,, wenn es eine goroutine sei, die einen Wert auf b, dann Auswertung von <- b in Schritt 2, und Sie würde nicht blockieren, so würde die Ausführung von select nicht stecken senden würden sehen würde, die "select worked as naively expected" erwartet (weil Empfangen von a konnte immer noch nicht damit fortfahren default gewählt werden würde):

go func() { b <- 1 }() 

select { 
    // ... 
} 

Versuchen sie es auf dem Go Playground.