2017-04-08 3 views
1

Ich bin neu in Go. Wenn ich die zweite Goroutine auskommentiere, gibt es einen fatalen Fehler. Ich verstehe nicht, was diesen Fehler verursacht. Kannst du es mir erklären?Deadlock zwischen goroutines

package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    ch := make(chan int) 
    go func() { 
     for i := 0; i < 10; i++ { 
      ch <- i 
     } 
    }() 
    // go func() { 
     for { 
      if num, ok := <-ch; !ok { 
       break 
      } else { 
       fmt.Printf("%d\n", num) 
      } 
     } 
    // }() 
    time.Sleep(2 * time.Second) 
    close(ch) 
} 

Dieser druckt den folgenden Code:

0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
fatal error: all goroutines are asleep - deadlock! 

goroutine 1 [chan receive]: 
main.main() 
    /tmp/sandbox169127128/main.go:17 +0xa0 

Program exited. 

Antwort

5

für die empfangende Schleifenblöcke auf von ch empfangen, nachdem alle Werte von der Sende goroutine empfängt. Die Laufzeit erkennt, dass das Programm blockiert und in Panik ist.

Die Fehlerbehebung wird der Kanal nach dem Senden aller Werte schließen:

go func() { 
    for i := 0; i < 10; i++ { 
     ch <- i 
    } 
    close(ch) 
}() 

auf dem geschlossenen Kanal Empfangen ergibt den Wert 0, false. Die empfangende Schleife unterbricht den falschen Wert.

Entfernen Sie close(ch) vom Ende des Programms.

Run it on the playground.

+0

Danke für die kurze Erläuterung, Cerise. Ich bin mir nicht sicher, ob ich die Idee des "Blockierens" vollständig verstehe. Bedeutet dies, dass die empfangende Schleife für immer hängen bleibt? Ist das so, weil das ok auf der linken Seite des Codes unten wahr wird, aber es wird niemals eine andere Zahl geben? wenn num, ok: = <-ch; ! ok – Pizzas

+0

@Puzzas: https://en.wikipedia.org/wiki/Blocking_(computing) In deinem Fall ist 'num, ok: = <-ch 'blockiert (wartet auf eine weitere Antwort). Diese andere Antwort kommt nie, weil die sendende Routine bereits beendet wurde. Wenn Sie den Kanal in der Send-Go-Routine schließen, wird eine weitere Antwort (die anzeigt, dass der Kanal geschlossen wurde) empfangen. – Flimzy

+0

@Pizzas Empfangen auf einem offenen Kanal wartet auf einen Wert, der an den Kanal gesendet wird. Die Empfangsschleife wartet für immer, nachdem alle Werte von der sendenden goroutine empfangen worden sind. –

2

Weil Sie den Kanal nicht schließen, bevor die erste Goroutine beendet wird. Der folgende Code sollte funktionieren.

package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    ch := make(chan int) 
    go func() { 
     for i := 0; i < 10; i++ { 
      ch <- i 
     } 
     close(ch) 
    }() 
    //go func() { 
     for { 
      if num, ok := <-ch; !ok { 
       break 
      } else { 
       fmt.Printf("%d\n", num) 
      } 
     } 
    //}() 
    time.Sleep(2 * time.Second) 
} 

Probieren Sie es hier aus: https://play.golang.org/p/OdxNqbaZmj