我做了一个小程序来测试通道吞吐量,但是它总是死锁,我努力但却无法理解原因:
package main
import (
"fmt"
"runtime"
)
const CONCURRENCY = 32
const WORK_PER_WORKER = 100
const TOTAL_WORK = CONCURRENCY * WORK_PER_WORKER
func work() {
sum := 0
for i := 0; i < 10000000; i++ {
sum *= i
}
}
type WorkItem struct {
Done chan int
}
func main() {
runtime.GOMAXPROCS(CONCURRENCY)
var workQueue [CONCURRENCY]chan *WorkItem
// initialize workers
for i := 0; i < CONCURRENCY; i++ {
workQueue[i] = make(chan *WorkItem)
}
// start workers
for i := 0; i < CONCURRENCY; i++ {
go func(i int) {
anItem := <-workQueue[i]
work()
anItem.Done <- 1
}(i)
}
completed := make(chan bool, TOTAL_WORK)
for i := 0; i < TOTAL_WORK; i++ {
go func(i int) {
// send work to queues
workToDo := &WorkItem{Done: make(chan int)}
workQueue[i/WORK_PER_WORKER] <- workToDo // !! DEADLOCK
// wait until the work is done
<-workToDo.Done
completed <- true
}(i)
}
fmt.Println("Waiting")
for i := 0; i < TOTAL_WORK; i++ {
<-completed
}
}
答案 0 :(得分:2)
您的代码go func(i int) { anItem := <-workQueue[i]; ... }
会从workQueue[i]
中移除juste 1项,但您正在尝试将WORK_PER_WORKER项填充到其中。您将处理CONCURRENCY许多项目,然后所有阅读goroutines终止并且您有僵局。
在工作者goroutines中循环“解决”你的僵局:http://play.golang.org/p/j2pavqnBDv
只是“解决”,因为这些工人goroutines永远不会终止。也许您可以尝试close
您的频道,以便在没有任何内容发送时通知工作人员goroutines。
答案 1 :(得分:1)
因为您的工作人员只处理一项任务然后退出。因此,只有第一个CONCURRENCY
项目继续进行,然后workQueue[i/WORK_PER_WORKER] <- workToDo
无限制地阻止。因此,completed
chan永远不会收到足够的值,main
也会永久阻止。
你的工作人员应该循环工作,如下所示:
for i := 0; i < CONCURRENCY; i++ {
go func(i int) {
for anItem := range workQueue[i] {
work()
anItem.Done <- 1
}
}(i)
}