【问题标题】:Golang worker using wait groups使用等待组的 Golang 工作者
【发布时间】:2021-12-13 02:31:03
【问题描述】:

我是 Golang 的新手,并试图了解 Golang 中的 WaitGroups 和并发是如何工作的。在此示例中,创建了 5 个工作人员,并使用一个通道将工作传递给每个工作人员。工作人员被要求休眠 1 秒以模拟繁重的计算。一切顺利,但程序并没有优雅地退出。而是打印此错误消息。请帮助理解为什么会发生这种情况。

fatal error: all goroutines are asleep - deadlock!

这是代码,


import (
    "fmt"
    "sync"
    "time"
)

func worker(wg *sync.WaitGroup, messageChannel <-chan string) {
    defer wg.Done()
    for i := range messageChannel {
        time.Sleep(time.Second)
        fmt.Println("done processing - ", i)
    }
}

func stop(wg *sync.WaitGroup) {
    fmt.Println("waiting on the main thread")
    wg.Wait()
}

func main() {
    wg := new(sync.WaitGroup)
    messageChannel := make(chan string, 50)

    // create workers
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go worker(wg, messageChannel)
    }

    // input some messages
    for i := 0; i < 10; i++ {
        messageChannel <- fmt.Sprint(i)
    }

    stop(wg)
    close(messageChannel)
}

提前致谢!

【问题讨论】:

  • 在通道关闭之前工作人员无法退出(因为for range 是这样工作的),并且在工作人员完成之前通道不会关闭。在 main 结束时交换 stop 和 close 调用。

标签: go concurrency worker


【解决方案1】:

为了扩展@Peter 的评论,这里是您编写的代码的执行流程:

  • 初始化后,你启动你的worker goroutines。每个worker goroutine 的范围都会超过messageChannel,延迟 1 秒会打印出一条消息。
  • 接下来,您通过 for 循环在 messageChannel 中插入一些消息。每个可用的worker goroutine 都会收到一条消息,直到所有消息都被处理并打印出来。之后,worker goroutine 正在等待来自messageChannel 的新消息。
  • 在完成在messageChannel 中插入消息的for 循环后,执行stop 函数,该函数阻塞wg.Wait() 并等待所有wg.Done() 调用在所有worker goroutines 中执行.然而,由于messageChannel 没有关闭,worker goroutine 都无法完成执行,wg.Done() 调用也不会被执行。
  • worker goroutine 卡住了,因为 messageChannel 永远不会关闭,main goroutine 卡住了,因为 wg.Wait() 调用在 stop 函数内,你最终会陷入死锁,所有 goroutine 都在睡着了。

根据建议,您只需为 stopclose 调用交换位置

//rest of the code
close(messageChannel)
stop(wg)

这样,当所有消息都插入messageChannel 时,您调用close(messageChannel),然后调用stop(wg),这会阻塞wg.Wait 调用。 close(messageChannel) 调用确保,一旦从 messageChannel 读取所有消息,messageChannel 上的 for-range 循环将退出 worker goroutines,并执行所有 defer wg.Done() 调用。一旦发生这种情况,wg.Wait() 将解除阻塞,程序将正常执行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-06
    • 1970-01-01
    • 2020-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多