当前位置: 首页 > article >正文

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

  • 推荐学习文档
    • golang应用级os框架,欢迎star
    • golang应用级os框架使用案例,欢迎star
    • 案例:基于golang开发的一款超有个性的旅游计划app经历
    • golang实战大纲
    • golang优秀开发常用开源库汇总
    • 想学习更多golang知识,这里有免费的golang学习笔记专栏

文章目录

    • 引言
    • 协程管理中的常见问题
      • 1.协程泄漏
      • 2.协程过多导致资源耗尽
    • 解决方案
      • 1.避免协程泄漏
      • 2.限制协程数量
    • 总结

引言

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

协程管理中的常见问题

1.协程泄漏

  • 协程在执行过程中,如果由于某些原因(如阻塞在某个通道上、陷入死锁等)没有正常退出,就会导致协程泄漏。大量的协程泄漏会耗尽系统资源,如内存等。
  • 示例代码:
package main

import (
    "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 时间片、内存等)被大量占用,从而影响系统的性能和稳定性。
  • 示例代码:
package main

import (
    "fmt"
    "runtime"
    "sync"
)

func manyGoroutines() {
    var wg sync.WaitGroup
    for 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.避免协程泄漏

  • 合理使用通道和超时机制
    • 对于可能阻塞的通道操作,可以设置超时时间,避免协程无限制地等待。
  • 代码示例:
package main

import (
    "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)
    • 通过信号量来限制同时执行的协程数量。
  • 代码示例:
package main

import (
    "fmt"
    "sync"
)

// 定义信号量
var semaphore = make(chan struct{}, 10)

func limitedGoroutine() {
    // 获取信号量
    semaphore <- struct{}{}
    defer func() {
        // 释放信号量
        <-semaphore
    }()

    // 协程执行的操作
    fmt.Println("协程执行中...")
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func() {
            limitedGoroutine()
            wg.Done()
        }()
    }
    wg.Wait()
    fmt.Println("所有协程执行完毕")
}

总结

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

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


http://www.kler.cn/news/307750.html

相关文章:

  • Linux云计算 |【第三阶段】PROJECT1-DAY1
  • Spring Boot-自动配置问题
  • SQL题目分析:打折日期交叉问题--计算品牌总优惠天数
  • DDD的主要流程
  • Gson转换
  • Matlab simulink建模与仿真 第十六章(用户定义函数库)
  • matlab边缘点提取函数
  • debian服务器上搭建git服务及添加文件提交拉取的操作记录、在Ubuntu上搭建Jenkins服务以及Ubuntu中的PPA源及PPA的安装使用
  • 【C++学习】 IO 流揭秘:高效数据读写的最佳实践
  • 1×4矩阵键盘详解(STM32)
  • 基于小程序的教学辅助微信小程序设计+ssm(lw+演示+源码+运行)
  • 在Flask中实现跨域请求(CORS)
  • 建模杂谈系列256 规则函数化改造
  • Kotlin:1.9.0 的新特性
  • 鸿萌数据恢复服务:如何恢复 Mac 系统中被擦除的文件?
  • 网络高级项目( 基于webserver的工业数据采集和控制项目)
  • Https AK--(ssl 安全感满满)
  • 【LIO】FAST-LIO论文详解
  • 如何在C++中使用mupdf操作pdf文件(一)
  • 微信小程序页面制作——婚礼邀请函(含代码)
  • 深入探讨ES6高级特性与实际应用
  • 注册登录案列
  • 加密
  • 空间解析几何 1 :空间中直线、圆、椭圆的方程表示
  • 感知器神经网络
  • 【Qt】Qt C++ Widget中嵌入qml
  • Python酷库之旅-第三方库Pandas(120)
  • type和interface区别
  • redis 十大应用场景
  • 《Effective Debugging:软件和系统调试的66个有效方法》读书笔记-Part2