英文:
Fatal error: goroutines are asleep - deadlock
问题
尝试学习Go语言并发。我遇到了一个问题,错误信息如下:
fatal error: all goroutines are asleep - deadlock!
有人告诉我要添加一个waitgroup和一个close channel来解决这个问题。我已经添加了这两个,但错误仍然存在。不确定我做错了什么。
以下是我的代码:https://play.golang.org/p/ZB45oXlBUl
package main
import (
"log"
"sync"
"time"
)
type RowInfo struct {
id int64
}
func main() {
queueChan := make(chan RowInfo)
workerChan := make(chan RowInfo)
doneChan := make(chan int64)
closeChan := make(chan struct{})
var waitGroup sync.WaitGroup
go dispatcher(queueChan, workerChan, doneChan, closeChan)
// 启动WorkerCount个worker
workerCount := 4
for i := 0; i < workerCount; i++ {
go worker(workerChan, doneChan, &waitGroup)
}
// 发送测试数据
waitGroup.Add(12)
for i := 0; i < 12; i++ {
queueChan <- RowInfo{id: int64(i)}
}
// 等待所有任务完成
waitGroup.Wait()
close(closeChan)
}
func dispatcher(queueChan, workerChan chan RowInfo, doneChan chan int64, closeChan chan struct{}) {
state := make(map[int64]bool)
for {
select {
case job := <-queueChan:
if state[job.id] == true {
continue
}
workerChan <- job
case result := <-doneChan:
state[result] = false
case <-closeChan:
close(queueChan)
close(workerChan)
close(doneChan)
break
}
}
}
func worker(workerChan chan RowInfo, doneChan chan int64, waitGroup *sync.WaitGroup) {
for job := range workerChan {
time.Sleep(1 * time.Second)
log.Printf("正在处理任务行信息,ID:%d", job.id)
// 完成任务
doneChan <- job.id
waitGroup.Done()
}
}
以下是错误信息:
2009/11/10 23:00:01 正在处理任务行信息,ID:2
2009/11/10 23:00:01 正在处理任务行信息,ID:0
2009/11/10 23:00:01 正在处理任务行信息,ID:3
2009/11/10 23:00:01 正在处理任务行信息,ID:1
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/tmp/sandbox490337982/main.go:32 +0x1e0
goroutine 5 [chan send]:
main.dispatcher(0x104360c0, 0x10436100, 0x10436140, 0x10436180)
/tmp/sandbox490337982/main.go:50 +0x200
created by main.main
/tmp/sandbox490337982/main.go:21 +0x100
goroutine 6 [chan send]:
main.worker(0x10436100, 0x10436140, 0x104382e0, 0x0)
/tmp/sandbox490337982/main.go:68 +0x1a0
created by main.main
/tmp/sandbox490337982/main.go:26 +0x160
goroutine 7 [chan send]:
main.worker(0x10436100, 0x10436140, 0x104382e0, 0x0)
/tmp/sandbox490337982/main.go:68 +0x1a0
created by main.main
/tmp/sandbox490337982/main.go:26 +0x160
goroutine 8 [chan send]:
main.worker(0x10436100, 0x10436140, 0x104382e0, 0x0)
/tmp/sandbox490337982/main.go:68 +0x1a0
created by main.main
/tmp/sandbox490337982/main.go:26 +0x160
goroutine 9 [chan send]:
main.worker(0x10436100, 0x10436140, 0x104382e0, 0x0)
/tmp/sandbox490337982/main.go:68 +0x1a0
created by main.main
/tmp/sandbox490337982/main.go:26 +0x160
英文:
Trying to learn go concurrency. I was having an issue where I was getting an error of:
fatal error: all goroutines are asleep - deadlock!
And I was told to add a waitgroup and a close channel to fix that issue. I've added both of those, but the error still persists. Not sure what I'm doing wrong anymore.
Here's my code https://play.golang.org/p/ZB45oXlBUl:
package main
import (
"log"
"sync"
"time"
)
type RowInfo struct {
id int64
}
func main() {
queueChan := make(chan RowInfo)
workerChan := make(chan RowInfo)
doneChan := make(chan int64)
closeChan := make(chan struct{})
var waitGroup sync.WaitGroup
go dispatcher(queueChan, workerChan, doneChan, closeChan)
// Start WorkerCount number of workers
workerCount := 4
for i := 0; i < workerCount; i++ {
go worker(workerChan, doneChan, &waitGroup)
}
// Send test data
waitGroup.Add(12)
for i := 0; i < 12; i++ {
queueChan <- RowInfo{id: int64(i)}
}
// Prevent app close till finished execution
waitGroup.Wait()
close(closeChan)
}
func dispatcher(queueChan, workerChan chan RowInfo, doneChan chan int64, closeChan chan struct{}) {
state := make(map[int64]bool)
for {
select {
case job := <-queueChan:
if state[job.id] == true {
continue
}
workerChan <- job
case result := <-doneChan:
state[result] = false
case <-closeChan:
close(queueChan)
close(workerChan)
close(doneChan)
break
}
}
}
func worker(workerChan chan RowInfo, doneChan chan int64, waitGroup *sync.WaitGroup) {
for job := range workerChan {
time.Sleep(1 * time.Second)
log.Printf("Doing work on job rowInfo ID: %d", job.id)
// Finish job
doneChan <- job.id
waitGroup.Done()
}
}
And the errors:
2009/11/10 23:00:01 Doing work on job rowInfo ID: 2
2009/11/10 23:00:01 Doing work on job rowInfo ID: 0
2009/11/10 23:00:01 Doing work on job rowInfo ID: 3
2009/11/10 23:00:01 Doing work on job rowInfo ID: 1
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/tmp/sandbox490337982/main.go:32 +0x1e0
goroutine 5 [chan send]:
main.dispatcher(0x104360c0, 0x10436100, 0x10436140, 0x10436180)
/tmp/sandbox490337982/main.go:50 +0x200
created by main.main
/tmp/sandbox490337982/main.go:21 +0x100
goroutine 6 [chan send]:
main.worker(0x10436100, 0x10436140, 0x104382e0, 0x0)
/tmp/sandbox490337982/main.go:68 +0x1a0
created by main.main
/tmp/sandbox490337982/main.go:26 +0x160
goroutine 7 [chan send]:
main.worker(0x10436100, 0x10436140, 0x104382e0, 0x0)
/tmp/sandbox490337982/main.go:68 +0x1a0
created by main.main
/tmp/sandbox490337982/main.go:26 +0x160
goroutine 8 [chan send]:
main.worker(0x10436100, 0x10436140, 0x104382e0, 0x0)
/tmp/sandbox490337982/main.go:68 +0x1a0
created by main.main
/tmp/sandbox490337982/main.go:26 +0x160
goroutine 9 [chan send]:
main.worker(0x10436100, 0x10436140, 0x104382e0, 0x0)
/tmp/sandbox490337982/main.go:68 +0x1a0
created by main.main
/tmp/sandbox490337982/main.go:26 +0x160
答案1
得分: 1
为了理解这个问题,我们需要考虑dispatcher
和workers
之间的情况。
- 初始状态:
dispatcher
和workers
都处于空闲状态。 - 在
queueChan
上发送消息:dispatcher
选择将消息发送到workerChan
。 worker
从workerChan
读取消息:休眠4秒钟,然后将消息写入doneChan
。- 步骤2和3重复4次,直到所有的
worker
都处于休眠状态。 - 当所有的
worker
都处于休眠状态时,另一个任务通过queueChan
进入。 dispatcher
开始执行该任务。dispatcher
无法在workerChan
上发送消息,因为没有worker
在读取消息。- 所有的
worker
完成休眠后,尝试在doneChan
上发送消息。
现在所有的goroutine都被阻塞了。
英文:
In order to understand the issue, think about what is going on with the dispatcher
and the workers
.
- Initial state: dispatcher and workers are idle
- Send on queueChan: dispatcher select sends to workerChan
- workerChan read by worker: sleep 4 seconds, write to doneChan.
- 2, 3 is repeated 4 times until all workers are sleeping
- While all workers are sleeping, another job comes in on queueChan.
- dispatcher goes to do that work
- dispatcher can not send on workerChan because no workers are reading.
- all workers get through their sleep and try to send on doneChan.
Now all goroutines are blocked.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论