我做了一个小程序来测试go通道的吞吐量,但是它总是死锁,我非常努力,但不明白为什么:
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
}
}发布于 2014-01-08 23:22:14
您的代码go func(i int) { anItem := <-workQueue[i]; ... }从workQueue[i]中删除了仅1项,但是您正在尝试将WORK_PER_WORKER项填充到其中。您将处理多个项的并发性,在此之后,所有的阅读对象都已终止,并且您将陷入死锁。
在员工大猩猩中循环“解决”了您的死锁:http://play.golang.org/p/j2pavqnBDv只是“解决”了,因为这些员工大猩猩永远不会终止。也许你可以尝试在你的频道上使用close来通知工作人员什么时候什么都不会发送。
发布于 2014-01-08 23:22:04
因为您的员工只处理一个任务,然后退出。因此,只有第一个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)
}https://stackoverflow.com/questions/21007259
复制相似问题