golang学习笔记21——golang协程管理及sync.WaitGroup的使用

devtools/2024/10/21 9:19:13/

文章目录

引言

Golang 中的协程(goroutine)为并发编程带来了极大的便利,但在实际开发中,如果对协程管理不当,也会产生一系列问题。本文将深入探讨这些问题,并结合代码示例给出相应的解决方案。

协程管理中的常见问题

1.协程泄漏

  • 协程在执行过程中,如果由于某些原因(如阻塞在某个通道上、陷入死锁等)没有正常退出,就会导致协程泄漏。大量的协程泄漏会耗尽系统资源,如内存等。
  • 示例代码:
golang">package mainimport ("fmt""time"
)func leakyGoroutine() {// 这个协程会一直阻塞,导致协程泄漏<-make(chan int)
}func main() {for i := 0; i < 10; i++ {go leakyGoroutine()}// 主线程休眠一段时间,让协程有机会执行time.Sleep(5 * time.Second)fmt.Println("程序结束,但协程泄漏了")
}

2.协程过多导致资源耗尽

  • 创建过多的协程而没有进行有效的限制和管理,会使系统资源(如 CPU 时间片、内存等)被大量占用,从而影响系统的性能和稳定性。
  • 示例代码:
golang">package mainimport ("fmt""runtime""sync"
)func manyGoroutines() {var wg sync.WaitGroupfor i := 0; i < 100000; i++ {wg.Add(1)go func() {// 模拟协程执行一些简单的操作for j := 0; j < 1000; j++ {_ = j}wg.Done()}()}wg.Wait()
}func main() {before := runtime.NumGoroutine()manyGoroutines()after := runtime.NumGoroutine()fmt.Printf("创建前协程数量: %d, 创建后协程数量: %d\n", before, after)
}

解决方案

1.避免协程泄漏

  • 合理使用通道和超时机制
    • 对于可能阻塞的通道操作,可以设置超时时间,避免协程无限制地等待。
  • 代码示例:
golang">package mainimport ("fmt""time"
)func nonLeakyGoroutine() {// 创建一个带超时的通道timeout := time.After(3 * time.Second)ch := make(chan int)go func() {// 模拟可能阻塞的操作time.Sleep(5 * time.Second)ch <- 1}()select {case <-ch:fmt.Println("协程正常接收数据")case <-timeout:fmt.Println("操作超时,协程退出")}
}func main() {for i := 0; i < 10; i++ {go nonLeakyGoroutine()}// 主线程休眠一段时间time.Sleep(5 * time.Second)fmt.Println("程序结束,没有协程泄漏")
}
  • 避免死锁
    • 在多个协程之间进行同步和通信时,要确保资源的获取和释放顺序正确,避免出现死锁导致协程无法退出。

2.限制协程数量

  • 使用信号量(Semaphore)
    • 通过信号量来限制同时执行的协程数量。
  • 代码示例:
golang">package mainimport ("fmt""sync"
)// 定义信号量
var semaphore = make(chan struct{}, 10)func limitedGoroutine() {// 获取信号量semaphore <- struct{}{}defer func() {// 释放信号量<-semaphore}()// 协程执行的操作fmt.Println("协程执行中...")
}func main() {var wg sync.WaitGroupfor i := 0; i < 100; i++ {wg.Add(1)go func() {limitedGoroutine()wg.Done()}()}wg.Wait()fmt.Println("所有协程执行完毕")
}

总结

在 Go 语言中,协程管理是并发编程的关键部分。通过避免协程泄漏和合理限制协程数量等措施,可以有效地提高程序的性能和稳定性,充分发挥 Go 语言在并发编程方面的优势。

关注我看更多有意思的文章哦!👉👉


http://www.ppmy.cn/devtools/113251.html

相关文章

如何使用Spring框架来实现一个基于SSM(Spring、SpringMVC、MyBatis)的整合项目

目录 1. 项目结构概述 2. 配置和整合 Spring配置 数据源配置&#xff08;DataSourceConfig&#xff09; MyBatis配置 3. 开发业务逻辑 实体类&#xff08;Domain&#xff09; 数据访问对象&#xff08;DAO&#xff09; 服务层&#xff08;Service&#xff09; 4. 处理…

Kafka 基础与架构理解

目录 前言 Kafka 基础概念 消息队列简介&#xff1a;Kafka 与传统消息队列&#xff08;如 RabbitMQ、ActiveMQ&#xff09;的对比 Kafka 的组件 Kafka 的工作原理&#xff1a;消息的生产、分发、消费流程 Kafka 系统架构 Kafka 的分布式架构设计 Leader-Follower 机制与…

SpringBoot 消息队列RabbitMQ 消息可靠性 数据持久化 与 LazyQueue

介绍 在默认情况下&#xff0c;RabbitMQ会将接收到的信息保存在内存中以降低消息收发的延迟 一旦MO宕机&#xff0c;内存中的消息会丢失内存空间有限&#xff0c;当消费者故障或处理过慢时&#xff0c;会导致消息积压&#xff0c;引发MQ阻塞 在消息队列运行的过程中&#xf…

泛读笔记:从Word2Vec到BERT

自然语言处理(NLP)模型的发展历史 1.统计方法时期&#xff1a;使用贝叶斯方法、隐马尔可夫模型、概率模型等传统统计方法 2.机器学习时期&#xff1a;支持向量机(SVM)、决策树模型、随机森林、朴素贝叶斯等传统机器学习方法 3.深度学习革命&#xff1a;各种新的深度学习模型&am…

C语言实现贪吃蛇小游戏

✅博客主页:爆打维c-CSDN博客​​​​​​ &#x1f43e; &#x1f539;分享c语言知识及代码 &#x1f43e; 目录 游戏展示视频 一、项目准备工作 二、功能实现分析 1.游戏开始 a.设置本地化、创建窗口、标题 b.隐藏光标,封装定位光标的函数 c.打印欢迎界面及提示信息 …

风力发电叶片缺陷检测数据集

风力发电叶片缺陷检测数据集】nc: 4 names: [Burn Mark, Coating_defects, Crack, EROSION ] 名称&#xff1a;【烧伤痕迹, 涂层缺陷, 裂缝&#xff0c;侵蚀】共1095张&#xff0c;8:1:1比例划分&#xff0c;&#xff08;train;876张&#xff0c;val&#xff1a;109张&#xff…

C#泛型(Generic)

泛型&#xff08;Generic&#xff09;允许延迟编写类或方法中的编程元素的数据类型的规范&#xff0c;直到实际在程序中使用它的时候。换句话说&#xff0c;泛型允许编写一个可以与任何数据类型一起工作的类或方法。 可以通过数据类型的替代参数编写类或方法的规范。当编译器遇…

vue之我不会

一、计算属性 例子&#xff1a; 注意&#xff1a;调用计算属性时&#xff0c;不可以带括号&#xff0c;那样调用的就是方法&#xff0c;如&#xff1a;以下调用fullName时不可funnName() <div id"root">姓&#xff1a;<input type"text" v-model&…