【问题标题】:Fatal error: goroutines are asleep - deadlock致命错误:goroutines 处于睡眠状态 - 死锁
【发布时间】:2016-02-12 07:36:20
【问题描述】:

尝试学习 Go 并发。我遇到了以下错误:

fatal error: all goroutines are asleep - deadlock!

我被告知要添加一个等待组和一个关闭频道来解决这个问题。我已经添加了这两个,但错误仍然存​​在。不知道我在做什么错了。

这是我的代码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()
    }
}

还有错误:

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

【问题讨论】:

标签: go


【解决方案1】:

为了理解这个问题,想想dispatcherworkers 发生了什么。

  1. 初始状态:调度员和工作人员处于空闲状态
  2. 在 queueChan 上发送:调度程序选择发送到 workerChan
  3. workerChan 读取 worker:休眠 4 秒,写入 doneChan。
  4. 2、3 重复 4 次,直到所有工作人员都睡觉
  5. 当所有工作人员都在睡觉时,queueChan 上出现了另一个作业。
  6. 调度员去做那项工作
  7. 调度员无法发送 workerChan,因为没有工作人员正在阅读。
  8. 所有工作人员都熬过睡眠并尝试发送 doneChan。

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

【讨论】:

  • 啊,太好了,谢谢,现在我明白了!像这样布置真的很有帮助。那么你有什么推荐的方法来解决这个问题而不使用缓冲通道吗?我想不出任何简单的解决方案,如果可以的话,我想避免使用缓冲通道。
  • 您可以将第 51 行更改为 go func() { workerChan &lt;- job }() 以便调度员继续进行
猜你喜欢
  • 2016-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-22
  • 2015-04-02
相关资源
最近更新 更多