2017-01-21 3 views
1

Ich bin in einer seltsamen Situation fest, wo die Schreiboperation auf den Kanal nie passiert.Schreiben auf Kanal blockiert für immer

package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    c := make(chan int) 
    s := make(chan bool) 
    k := make(chan bool) 
    fmt.Println("start") 
    go func() { 
    fmt.Println("routine 1") 
     s <- true 
    }() 
    go func() { 
    fmt.Println("routine 2") 
     for { 
      select { 
      case <-s : 
       for i := 0; i < 3; i++ { 
        fmt.Println("before") 
        c <- i 
        fmt.Println("after") 
       }  
      case <- k : 
       fmt.Println("k ready") 
       break 
      } 
     } 
    }() 

    go func() { 
     fmt.Println("routine 3") 
     for { 
      select { 
       case x := <- c : 
       fmt.Println("x=", x) 
       k <- true 
       fmt.Println("k done") 

      } 
     } 
    }() 

    time.Sleep(1000 * time.Millisecond) 
} 

Und hier ist die Ausgabe:

start 
routine 1 
routine 2 
before 
routine 3 
x= 0 
after 
before 

Ich frage mich, warum das Schreiben in den Kanal k Blöcke, aber die Log-Anweisung fmt.Println("k ready") nie gedruckt wird. Hier

ist, was ich denke:

  • gehen Routine 1 schreibt wahr Kanal s
  • gehen Routine 2 0 bis Kanal c schreibt und wartet, weil Puffergröße 0 ist, wird es nicht möglich sein, Schreiben Sie '1' zu ihm, es sei denn, jemand liest Kanal c
  • gehen Routine 3 kommt in das Bild, liest Kanal c (jetzt gehen Routine 2 kann schreiben c einmal gehen Routine 2 setzt fort) druckt den Wert von x. Jetzt sollte es MÖGLICH ZU KANAL K zu schreiben, aber das geschieht nicht

mich nach ihm zu Kanal k dann Fall 2 von goroutine schreiben können sollten ausführen soll und print „k ready“

Kann mir jemand erklären, warum auf den blockierten Kanal schreiben? Als Fix weiß ich, ich kann die Puffergröße von Kanal c erhöhen und alles wird gedruckt, aber ich bin nicht daran interessiert, dies zu beheben, stattdessen möchte ich dieses Szenario verstehen.

Eine nette blog, um den obigen Fall zu verstehen.

+0

Link zu obigen Code ist [hier] (https://play.golang.org/p/3YL2eoTVn1) –

Antwort

1

Sie haben einen Deadlock.

  • goroutine 1 schreibt s dann beendet
  • goroutine 2 von s liest und schreibt auf c
  • goroutine 3 von c liest und schreibt zu k, und diese Blöcke, weil nichts aus k Lesen, weil Goroutine 2 in dem Schreiben zu k oben blockiert wird.
  • goroutine 2 schreibt c wieder die Blöcke als goroutine 3 noch versucht, k und damit von c

Im Gegensatz zu lesen ist, nicht zu schreiben, was Sie sagen, Sie haben nicht eine Puffergröße von 1 Sie haben eine Puffergröße von Null (dh einen ungepufferten Kanal), so dass ein Schreibvorgang blockiert, bis etwas gelesen wird. Dies ist wahrscheinlich die Ursache für dein Missverständnis. Per dem language specification:

Ein neuer, initialisiert Kanalwert gemacht werden, kann die eingebaute Funktion make verwenden, die den Kanaltyp und eine optionale Funktion als Argument nimmt:

make(chan int, 100) 

die Kapazität, die in Anzahl der Elemente, legt die Größe des Puffers im Kanal fest.Wenn die Kapazität null ist oder nicht vorhanden ist, ist der Kanal ungepuffert und die Kommunikation ist nur erfolgreich, wenn sowohl ein Sender als auch ein Empfänger bereit sind. Andernfalls wird der Kanal gepuffert und die Kommunikation wird ohne Blockierung erfolgreich ausgeführt, wenn der Puffer nicht voll ist (sendet) oder nicht leer (empfängt). Ein Nullkanal ist niemals für die Kommunikation bereit.

+0

Dank @abligh für die Antwort, aber es scheint, wie es einige Tippfehler ist oder ich falsch verstanden Ihre Antwort. Punkt # 2: schreibe auf Kanal k geschieht in Go-Routine 3 Auch goroutine 3 wird nie wie Sie ausführen? –

+0

Und verstehen Sie das Puffergröße-Konzept, das Sie erwähnen, aber ich sagte fälschlicherweise Größe 1 statt 0, ich lese das [hier] (https://blog.golang.org/pipelines). Danke für die Korrektur. –

+0

@sheiksabeer Ich habe Deadlock-Erklärung – abligh

Verwandte Themen