go - 使用等待组的 Golang 工作者
问题描述
我是 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)
}
提前致谢!
解决方案
为了扩展@Peter 的评论,这里是您编写的代码的执行流程:
- 初始化后,你启动你的
worker
goroutines。每个worker
goroutine 都会超过messageChannel
,延迟 1 秒会打印出一条消息。 - 接下来,您
messageChannel
通过 for 循环插入一些消息。每个可用worker
的 goroutine 都会收到一条消息,直到所有消息都被处理并打印出来。之后,worker
goroutines 正在等待来自messageChannel
. - 在用于在中插入消息的 for 循环
messageChannel
完成后,您执行该stop
函数,该函数阻塞wg.Wait()
并等待所有wg.Done()
调用在所有worker
goroutine 中执行。然而,由于messageChannel
没有关闭,没有一个worker
goroutine 可以完成执行,也没有一个wg.Done()
调用被执行。 worker
goroutines 被卡住是因为它messageChannel
永远不会关闭,main
goroutines 因为函数wg.Wait()
内部的调用而被卡住stop
,你最终会陷入一个所有 goroutines 都处于休眠状态的死锁。
根据建议,您只需要交换地点stop
和close
电话
//rest of the code
close(messageChannel)
stop(wg)
这样,当所有消息都插入到 中时messageChannel
,您调用close(messageChannel)
然后stop(wg)
,这会阻塞wg.Wait
调用。该close(messageChannel)
调用确保,一旦从 中读取所有消息messageChannel
,goroutine内部的for-range
循环将退出,并且所有调用都将被执行。一旦发生这种情况,将解除阻塞,程序将正确完成执行。messageChannel
worker
defer wg.Done()
wg.Wait()
推荐阅读
- javascript - agora中的屏幕共享和视频广播切换错误
- reactjs - “%22”添加到生产构建中的 URL 路径?
- jenkins-job-dsl - 如何在 DSL 作业参数块中指定 buildSelectorParam?
- javascript - String to Number 在 JavaScript 中返回错误的结果
- nginx - Nginx 403 禁止位置和本地主机
- django - 如何让我的 django 服务器使用客户的打印机打印收据?
- c++ - 乘法/除法顺序(?)混淆
- php - Symfony 4.4(装饰)中的覆盖控制器 - “你请求了一个不存在的服务”
- python - 如何使用 Python 脚本启动 Windows?
- java - 如何将 javax.swing.ImageIcon 绘制到 JavaFX .fxml 呈现的用户界面中?