英文:
Why are my channels deadlocking?
问题
我正在尝试编写一个简单的Go脚本,用于计算自然数的总和,直到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)
}
然而,运行此程序会产生以下输出。
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
为什么我的代码发生了死锁?我感到困惑,因为我使用了两个独立的通道来计算子总和。这两个通道有什么依赖关系吗?
英文:
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?
答案1
得分: 6
你的通道是无缓冲的,所以在sum()
函数中的c <- sum
这一行会阻塞,直到其他协程从另一端读取。
一种选择是给通道添加缓冲区,这样你可以在不阻塞的情况下向通道写入值:
c1 := make(chan int, 1)
c2 := make(chan int, 1)
另外,如果你将sum()
函数作为一个单独的goroutine运行,那么它可以在main()
函数继续执行到从通道读取的地方时阻塞。
英文:
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.
答案2
得分: 5
是的,你需要像这样添加go
:
go sum(allNums[:len(allNums)/2], c1)
go sum(allNums[len(allNums)/2:], c2)
或者
c1 := make(chan int,1)
c2 := make(chan int,1)
添加通道缓存。
英文:
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.
答案3
得分: 2
我已经有一段时间没有使用Go了,所以这可能不是这种情况,但根据我记得的,你需要使用go
来启动另一个goroutine,所以:
go sum(allNums[:len(allNums)/2], c1)
go sum(allNums[len(allNums)/2:], c2)
如果sum
没有在另一个goroutine上运行,它会尝试执行:
c <- sum
但是没有任何地方读取c
;读取c
的代码还没有被执行,因为它正在等待sum
完成,而sum
无法完成,因为它需要先将结果给那段代码!
英文:
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!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论