I'm trying to do this tutorial -
https://tour.golang.org/concurrency/8
This is my code
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t != nil {
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right,ch)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for i:= range ch1 {
if i != <-ch2 {
return false
}
}
return true
}
func main() {
isSame := Same(tree.New(1), tree.New(1))
if isSame {
fmt.Println("SAME")
} else {
fmt.Println("DIFF")
}
}
But I get this error-
fatal error: all goroutines are asleep - deadlock!
It worked once, and then I ran it again and it stopped working...either that or I'm crazy.
What's going on?
The problem is that you never close ch1
, so your for i:= range ch1
loop never finishes; it just reads until there are no values in the channel, and then it blocks. At this point, there will be only one goroutine, and it's blocked listening to the empty channel, so Go will abort with the message you see. (Similarly, you never close ch2
, but in your case that doesn't happen to matter. That would cause a deadlock if ch2
ever had fewer values than ch1
.)
To be honest, I'm not sure exactly what solution the "Tour of Go" folks had in mind.
One option, which would work but is totally cheating, is to hard-code the fact that you'll only see ten values:
for i := 0; i < 10; i++ {
if <-ch1 != <-ch2 {
return false
}
}
A better option is for Same
to use anonymous functions that invoke Walk
and then close the channel:
go func() {
Walk(t1, ch1)
close(ch1)
}()
(or you could use a non-anonymous function for that; call it walkAndClose
or something).
Incidentally, your Same
function assumes that the two trees have the same sizes. If t1
has more elements, then t2
will be implicitly padded with zeroes at the end (since <-ch2
returns 0
once ch2
is closed and exhausted), and if t1
is shorter, then t2
will be implicitly truncated at the end. Maybe you're O.K. with making that assumption for the purposes of this exercise, but if you wanted Same
to always return false
for trees of different sizes, you could change your loop to:
for i := range ch1 {
j, receivedJ := <-ch2
if i != j || ! receivedJ {
return false
}
}
_, receivedJ := <-ch2
if receivedJ {
return false
}
(where I've used the two-return-value form of <-ch2
to detect whether the channel has been closed and exhausted; receivedJ
will be true
if <-ch2
returned an actual value from the channel, and false
if it returned a 0
by default).