Gehen Kanäle und deadlock
Ich versuche zu verstehen, Gehen Sprache. Ich habe versucht, zwei goroutines
Kette, die zwischen Ihnen fließen über zwei Kanäle:
func main() {
c1 := make(chan int)
c2 := make(chan int)
go func() {
for i := range c1{
println("G1 got", i)
c2 <- i
}
}()
go func() {
for i := range c2 {
println("G2 got", i)
c1 <- i
}
}()
c1 <- 1
time.Sleep(1000000000 * 50)
}
Als erwartet, dass dieser code druckt:
G1 got 1
G2 got 1
G1 got 1
G2 got 1
....
Bis die main-Funktion beendet.
Aber wenn ich senden einen anderen Wert, um einen der Kanäle aus Haupt -, plötzlich blockiert:
func main() {
c1 := make(chan int)
c2 := make(chan int)
go func() {
for i := range c1{
println("G1 got", i)
c2 <- i
}
}()
go func() {
for i := range c2 {
println("G2 got", i)
c1 <- i
}
}()
c1 <- 1
time.Sleep(1000000000 * 1)
c1 <- 2
time.Sleep(1000000000 * 50)
}
Gibt es
G1 got 1
G2 got 1
G1 got 1
G2 got 1
G1 got 2
und dann blockiert, bis der main endet.
Den Wert "2" an c1 kommt auf den ersten goroutie, die sendet auf c2, aber der zweite
goroutine nie erhält.
(Mit gepufferten Kanälen mit Größe 1 (entweder c1 oder c2) arbeitet in diesem Beispiel)
Warum ist es passiert? Wenn dies geschieht in realen code, wie kann ich Debuggen?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gehen-Kanäle erstellt, die mit
make(chan int)
sind nicht gepuffert. Wenn Sie möchten, dass ein Gepufferter Kanal (das wird nicht unbedingt blockieren), damit es mitmake(chan int, 2)
wo 2 ist die Größe des Kanals.Dem, was über Ungepuffert-Kanälen ist, dass Sie auch synchron, so dass Sie immer block auf schreiben sowie Lesen.
Der Grund für die Blockaden ist, dass Sie Ihre erste goroutine wartet auf seinen
c2 <- i
zu beenden, während die zweite wartetc1 <- i
zu beenden, denn es war eine zusätzliche Sache inc1
. Der beste Weg, die ich gefunden habe, zu Debuggen, diese Art der Sache, wenn es passiert im echten code ist zu schauen, was die goroutines blockiert sind und denken, hart.Kann man auch umgehen das problem, indem Sie nur über synchrone Kanäle, wenn Sie wirklich benötigt werden.
nmichaels Recht mit seiner Antwort, aber ich dachte, ich möchte hinzufügen, dass es gibt Möglichkeiten, um herauszufinden, wo Sie sind Deadlocks beim Debuggen ein problem wie dieses.
Einfach ist, wenn Sie auf einem Unix-like OS, führen Sie den Befehl
Dies wird töten das Programm und geben Sie einen stack-trace für jede goroutine.
Ein etwas aufwändiger Weg ist das anfügen gdb.
Untersuchen Sie den stack und Variablen der aktiven goroutine als normal, aber es gibt keine einfache Möglichkeit zu wechseln goroutines, die ich kenne. Kann man den Schalter OS-threads in der üblichen Weise, aber, die möglicherweise nicht genug, um zu helfen.
kill -6
: einfachste Weg, um herauszufinden, wo ein Kanal blockiert ist!