我正在学习如何进行并发,并且我已将其编写为自己的应用程序,以便我可以在其工作后将其移植到不同的项目中。
我添加它的项目基本上会将RowInfo发送到全局QueueChannel,然后我的工作人员应该接受这项工作并进行处理。如果我将具有相同ID的两行排队,并且其中一行当前正由工作人员处理,我将从队列中删除重复行(您可以在调度程序中看到我在“继续”的位置)。
此排队/工作人员代码将在阻止ListenAndServe的Web服务器上运行,因此我希望它始终保持运行,并且工作人员始终保持积极寻找工作。我不想关闭频道(除非我按c + +给应用程序或其他东西)。我怀疑我得到的错误与不关闭通道有关,因为这是很多其他线程提到这个错误似乎表明,但我不确定它与我所拥有的代码有什么关系。
终端错误输出:
[~/go/src/github.com/zzz/asynch]> go run main.go
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/home/zzz/go/src/github.com/zzz/asynch/main.go:29 +0x14b
goroutine 5 [select]:
main.diszzzcher(0xc82001a120, 0xc82001a180, 0xc82001a1e0)
/home/zzz/go/src/github.com/zzz/asynch/main.go:42 +0x21a
created by main.main
/home/zzz/go/src/github.com/zzz/asynch/main.go:19 +0xb1
goroutine 6 [chan receive]:
main.worker(0xc82001a180, 0xc82001a1e0)
/home/zzz/go/src/github.com/zzz/asynch/main.go:55 +0x54
created by main.main
/home/zzz/go/src/github.com/zzz/asynch/main.go:24 +0xf7
goroutine 7 [chan receive]:
main.worker(0xc82001a180, 0xc82001a1e0)
/home/zzz/go/src/github.com/zzz/asynch/main.go:55 +0x54
created by main.main
/home/zzz/go/src/github.com/zzz/asynch/main.go:24 +0xf7
goroutine 8 [chan receive]:
main.worker(0xc82001a180, 0xc82001a1e0)
/home/zzz/go/src/github.com/zzz/asynch/main.go:55 +0x54
created by main.main
/home/zzz/go/src/github.com/zzz/asynch/main.go:24 +0xf7
goroutine 9 [chan receive]:
main.worker(0xc82001a180, 0xc82001a1e0)
/home/zzz/go/src/github.com/zzz/asynch/main.go:55 +0x54
created by main.main
/home/zzz/go/src/github.com/zzz/asynch/main.go:24 +0xf7
exit status 2
代码:
package main
import (
"log"
"time"
)
type RowInfo struct {
id int64
}
var QueueChan chan RowInfo
func main() {
QueueChan := make(chan RowInfo)
workerChan := make(chan RowInfo)
exitChan := make(chan int64)
go dispatcher(QueueChan, workerChan, exitChan)
// Start WorkerCount number of workers
workerCount := 4
for i := 0; i < workerCount; i++ {
go worker(workerChan, exitChan)
}
// Send test data
for i := 0; i < 12; i++ {
QueueChan <- RowInfo{id: int64(i)}
}
// Prevent app close
for {
time.Sleep(1 * time.Second)
}
}
func dispatcher(queueChan, workerChan chan RowInfo, exitChan chan int64) {
state := make(map[int64]bool)
for {
select {
case job := <-QueueChan:
if state[job.id] == true {
continue
}
workerChan <- job
case result := <-exitChan:
state[result] = false
}
}
}
func worker(workerChan chan RowInfo, exitChan chan int64) {
for job := range workerChan {
log.Printf("Doing work on job rowInfo ID: %d", job.id)
// Finish job
exitChan <- job.id
}
}
谢谢。
答案 0 :(得分:5)
错误告诉你:所有goroutine都处于睡眠状态,程序已经死锁。
现在为什么你的所有goroutines都睡着了?让我们逐个检查:
worker
goroutines:无限期等待workerChan
上的新工作,在workerChan
关闭之前不会退出,等待新工作时才会睡着dispatcher
goroutine:永远循环,选择两个频道。永远不会退出,在select
main
goroutine:永远在time.Sleep
循环,大部分时间都不会退出并睡着通常情况下,在这种情况下,您会引入chan struct{}
(称之为closing
或类似的内容)并将其包含在select
中。如果您想关闭该程序,只需close(closing)
。 select
将选择<-closing
选项,您将返回goroutines。
您还应添加sync.WaitGroup
以便在所有goroutine退出时收到通知。