致命错误:goroutine 处于休眠状态 – 死锁

huangapple go评论85阅读模式
英文:

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 (
&quot;log&quot;
&quot;sync&quot;
&quot;time&quot;
)
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 &lt; workerCount; i++ {
go worker(workerChan, doneChan, &amp;waitGroup)
}
// Send test data
waitGroup.Add(12)
for i := 0; i &lt; 12; i++ {
queueChan &lt;- 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 := &lt;-queueChan:
if state[job.id] == true {
continue
}
workerChan &lt;- job
case result := &lt;-doneChan:
state[result] = false
case &lt;-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(&quot;Doing work on job rowInfo ID: %d&quot;, job.id)
// Finish job
doneChan &lt;- 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

为了理解这个问题,我们需要考虑dispatcherworkers之间的情况。

  1. 初始状态:dispatcherworkers都处于空闲状态。
  2. queueChan上发送消息:dispatcher选择将消息发送到workerChan
  3. workerworkerChan读取消息:休眠4秒钟,然后将消息写入doneChan
  4. 步骤2和3重复4次,直到所有的worker都处于休眠状态。
  5. 当所有的worker都处于休眠状态时,另一个任务通过queueChan进入。
  6. dispatcher开始执行该任务。
  7. dispatcher无法在workerChan上发送消息,因为没有worker在读取消息。
  8. 所有的worker完成休眠后,尝试在doneChan上发送消息。

现在所有的goroutine都被阻塞了。

英文:

In order to understand the issue, think about what is going on with the dispatcher and the workers.

  1. Initial state: dispatcher and workers are idle
  2. Send on queueChan: dispatcher select sends to workerChan
  3. workerChan read by worker: sleep 4 seconds, write to doneChan.
  4. 2, 3 is repeated 4 times until all workers are sleeping
  5. While all workers are sleeping, another job comes in on queueChan.
  6. dispatcher goes to do that work
  7. dispatcher can not send on workerChan because no workers are reading.
  8. all workers get through their sleep and try to send on doneChan.

Now all goroutines are blocked.

huangapple
  • 本文由 发表于 2016年2月12日 06:56:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/35351751.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定