为什么我的频道陷入僵局?

为什么我的频道陷入僵局?

问题描述:

I am trying to program a simple Go script that calculates the sum of the natural numbers up to 8:

package main
import "fmt" 

func sum(nums []int, c chan int) {
    var sum int = 0
    for _, v := range nums {
        sum += v    
    }
    c <- sum
}

func main() {
    allNums := []int{1, 2, 3, 4, 5, 6, 7, 8}
    c1 := make(chan int)
    c2 := make(chan int)
    sum(allNums[:len(allNums)/2], c1)
    sum(allNums[len(allNums)/2:], c2)
    a := <- c1
    b := <- c2
    fmt.Printf("%d + %d is %d :D", a, b, a + b)
}

However, running this program produces the following output.

throw: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.sum(0x44213af00, 0x800000004, 0x420fbaa0, 0x2f29f, 0x7aaa8, ...)
    main.go:9 +0x6e
main.main()
    main.go:16 +0xe6

goroutine 2 [syscall]:
created by runtime.main
    /usr/local/go/src/pkg/runtime/proc.c:221

exit status 2

Why is my code deadlocking? I am confused because I am using 2 separate channels to calculate the sub-sums. How are the two channels dependent at all?

Yes, you need to add go like

go sum(allNums[:len(allNums)/2], c1)

go sum(allNums[len(allNums)/2:], c2)

or

c1 := make(chan int,1)
c2 := make(chan int,1)

add channel cache.

I haven't used Go in a while, so this may not be the case, but from what I remember you need go to get another goroutine started, so:

go sum(allNums[:len(allNums)/2], c1)
go sum(allNums[len(allNums)/2:], c2)

If sum isn't running on another goroutine, it tries to execute:

c <- sum

But nothing's reading c; the code reading c has not been reached yet because it's waiting for sum to finish, and sum won't finish because it needs to give it to that code first!

Your channels are unbuffered, so the c <- sum line in sum() will block until some other routine reads from the other end.

One option would be to add buffers to the channels, so you can write a value to the channel without it blocking:

c1 := make(chan int, 1)
c2 := make(chan int, 1)

Alternatively, if you run the sum() function as a separate goroutine, then it can block while your main() function continues to the point where it reads from the channels.