我正在学习 Go,并且正在玩 Goroutines 和 channel 。我正在使用两个缓冲 channel 编写一个非常人为和天真的工作池,一个用于输入,一个用于输出。
现在我在添加作业后关闭我的输入 channel ,然后最终读取输出 channel 以从中读取结果,但是当我使用 for val := range ch
作为输出时程序因死锁而 panic 。这是示例代码
package main
import (
"fmt"
"time"
)
func main() {
st := time.Now()
jobs := make(chan int, 100)
res := make(chan int, 100)
// Putting items to the jobs channel
for i := 0; i < 9; i++ {
jobs <- i
}
close(jobs)
go workerPool(jobs, res, 1)
// This causes the program to panic with deadlock
for v := range res {
fmt.Println(v)
}
// This works just fine and program does not panics
//for i := 0; i < 9; i++ {
// fmt.Println(<-res)
//}
ed := time.Now()
fmt.Println(ed.Sub(st))
}
func workerPool(ip <-chan int, op chan<- int, id int) {
for v := range ip {
fmt.Println("Worker", id, "working on ", v)
op <- 1
}
}
这是我看到的输出
Worker 1 working on 0
Worker 1 working on 1
Worker 1 working on 2
Worker 1 working on 3
Worker 1 working on 4
Worker 1 working on 5
Worker 1 working on 6
Worker 1 working on 7
Worker 1 working on 8
1
1
1
1
1
1
1
1
1
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
我知道当我使用传统的 for 循环
时,我正在获取我最初放入 jobs
channel 的确切数量的值 (9)。但是 for range
不应该自动处理这个问题吗?当没有更多数据要从 channel 读取时, channel 将发送 false
值并且循环将终止?
最佳答案
这个问题的解决方案非常明显,我所要做的就是关闭
worker 中的输出 channel ,range
开始正常工作,原因很明显。
func workerPool(ip <-chan int, op chan<- int, id int) {
for v := range ip {
fmt.Println("Worker", id, "working on ", v)
op <- fib(v)
}
close(op) // change made
}
关于go - 在缓冲 channel 上使用范围时程序中的死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55852807/