【golang学习之旅】Go 语言并发编程(goroutine、channel 的使用)

news/2025/2/10 21:31:28/

文章目录

    • 前言
    • 1. 为什么要学习 Go 语言并发编程?
    • 2. Goroutine(协程)详解
      • 2.1 什么是Goroutine?
      • 2.2 如何启动Goroutine?
      • 2.3 多个Goroutine并发执行
    • 3. Channel(通道)详解
      • 3.1 什么是Channel?
      • 3.2 创建 & 使用 Channel
      • 3.3 带缓冲的Channel
    • 4. Goroutine + Channel 实战应用
      • 4.1 生产者-消费者模型
    • 5. Go并发注意事项
    • 🎯 总结 & 进阶学习方向

前言

✅ 适合人群:Golang 开发者 | 并发编程初学者 | 后端开发工程师
✅ 文章亮点:深入解析 Goroutine & Channel + 代码示例 + 实战场景
✅ 目标:掌握 Go 并发编程核心,让你的代码更高效、更强大!

1. 为什么要学习 Go 语言并发编程?

在现代应用中,并发编程已成为后端开发的必备技能,特别是在高并发高性能需求的场景下,如:

  • WEB服务器:高并发请求处理(如GIn框架)
  • 微服务架构:高效处理RPC请求(如gRPC)
  • 消息队列:生产者 & 消费者模型(Kafka,RabbitMQ)
  • 爬虫系统:多线程抓取网页数据
  • 日志处理:日志采集 & 数据分析

🔹 Go 语言的并发特点:

  • 轻量级:Goroutine比操作系统线程更轻量,百万级并发毫无压力
  • 高效调度:Go运行时的GMP(Goroutine、线程、处理器)调度模型可高效管理线程
  • 简化并发编程:Go内置Channel(管道)让协程间通信更安全

本篇文章,我们将深入剖析 Goroutine(协程)与 Channel(通道),带你掌握 Go 并发编程的核心要领!

2. Goroutine(协程)详解

2.1 什么是Goroutine?

Goroutine是Go语言的轻量级线程,由Go运行时管理,而非操作系统。相比传统线程,Goroutine具备以下优点 :

  • 占用内存小:默认仅2KB栈空间,可动态扩展
  • 调度高效:Go运行时管理Goroutine的调度,无需手动创建线程
  • 启动成本低:创建Goroutine比创建线程的开销小很多

2.2 如何启动Goroutine?

使用Go关键字即可启动一个Goroutine

package main import ("fmt""time"
)// 定义一个函数
func hello() {fmt.Println("Hello, Goroutine!")
}func main() {go hello()  // 启动Goroutinetime.Sleep(time.Second)  // 主线程等待,防止提前退出
}

🔹 注意:

  1. go hello()直接让hello()运行在Goroutine
  2. Goroutine不等子Goroutine,若main()结束,子Goroutine也会结束,所以需要time.Sleep()让它运行一会儿

2.3 多个Goroutine并发执行

package mainimport ("fmt""time"
)func task(id int) {fmt.Println("Task %d running\n", id)time.Sleep(time.Second)
}func main() {for i := 0; i <= 5; i++ {go task(i)   // 启动多个Goroutine}time.Sleep(time.Second * 2)  // 等待Goroutine完成
}

📌 运行结果(每次可能不同):

Task 2 is running
Task 4 is running
Task 0 is running
Task 1 is running
Task 3 is running

🔹 因为 Goroutine 是并发执行的,所以任务顺序可能不固定。

3. Channel(通道)详解

3.1 什么是Channel?

Goroutine之间不能直接共享数据,而是通过Channel(通道)来进行线程安全的通信
🔹 Channel 的特点:

  • 用于Goroutine之间的数据传输
  • 类型安全(只能传输特定类型的数据)
  • 同步 & 阻塞(默认情况下是阻塞的)

3.2 创建 & 使用 Channel

package main import "fmt"func main() {ch := make(chan int) // 创建一个 int 类型的通道go func() {ch <- 10  // 发送数据}()value := <-ch  // 接收数据fmt.Println(value)   // 输出 10
}

🔹 重要概念:

  1. make(chan int)创建通道,传输int类型数据
  2. ch <- 10发送数据到通道(阻塞,直到有接收者)
  3. <-ch从通道接收数据(阻塞,直到通道有数据)

3.3 带缓冲的Channel

默认Channel无缓冲的,即发送 & 接收必须同步。可使用缓冲区提高效率:

ch := make(chan int, 2)  // 创建一个容量为 2 的缓存通道
ch <- 1
ch <- 2
fmt.Println(<ch) // 输出 1
fmt.Println(<ch) // 输出 2

🔹 缓冲通道的特点:
✅ 发送数据不一定阻塞(缓冲未满时)
✅ 接收数据不一定阻塞(缓冲未空时)

4. Goroutine + Channel 实战应用

4.1 生产者-消费者模型

package main import ("fmt""time"
)// 生产者
func producer(ch chan int){for i := 0; i < 5; i++ {fmt.Println("生产数据:", i)ch <- itime.Sleep(time.Millisecond * 500)}close(ch)  // 关闭通道
}// 消费者
func consumer(ch chan int){for value := range ch {fmt.Println("消费数据:", value)}
}func main() {ch := make(chan int, 3)  // 创建带缓冲通道go producer(ch)consumer(ch)
}

📌 运行结果(大致如下):

生产数据: 0
消费数据: 0
生产数据: 1
消费数据: 1
生产数据: 2
消费数据: 2

🔹 分析:

生产者(producer) 负责写入数据
消费者(consumer) 负责读取数据
range 读取通道数据,直到通道关闭

5. Go并发注意事项

✅ 主协程退出时,子 Goroutine 也会退出,所以需要sync.WaitGroup 等待所有协程执行完毕
✅ 避免数据竞争(race condition),可用 sync.Mutex 加锁
✅ 避免Goroutine 泄漏,使用context取消

🎯 总结 & 进阶学习方向

📌 本篇文章深入解析了 Go 并发编程的核心概念,包括 GoroutineChannel,帮助你掌握 Go 语言的高并发能力。
📌 进阶学习:Go 协程池、并发编程最佳实践、分布式系统设计
📌 学习资源:Go 官方文档


http://www.ppmy.cn/news/1570966.html

相关文章

如何写出优秀的单元测试?

写出优秀的单元测试需要考虑以下几个方面&#xff1a; 1. 测试用例设计 测试用例应该覆盖被测试代码的不同场景和边界情况&#xff0c;以尽可能发现潜在的问题。在设计测试用例时需要关注以下几点&#xff1a; 输入输出数据&#xff1a;要测试的函数或方法可能有多个输入参数…

c/c++蓝桥杯经典编程题100道(16)链表反转

链表反转 c/c蓝桥杯经典编程题100道-目录-CSDN博客 目录 链表反转 一、题型解释 二、例题问题描述 三、C语言实现 解法1&#xff1a;迭代反转&#xff08;难度★&#xff09; 解法2&#xff1a;递归反转&#xff08;难度★★&#xff09; 解法3&#xff1a;分组反转&am…

基于STM32的智能鱼缸水质净化系统设计

&#x1f91e;&#x1f91e;大家好&#xff0c;这里是5132单片机毕设设计项目分享&#xff0c;今天给大家分享的是智能鱼缸水质净化系统。 目录 1、设计要求 2、系统功能 3、演示视频和实物 4、系统设计框图 5、软件设计流程图 6、原理图 7、主程序 8、总结 1、设计要求…

大模型deepseek-r1 本地快速搭建

1、安装部署ollama 详细步骤见&#xff1a;Ollama 下载和安装 官网下载地址&#xff1a;Ollama官网 2、大模型Deepseekk-r1下载 详细步骤见&#xff1a;大模型deepseek-r1 本地ollama部署详解 ollama run deepseek-r13、Open WebUI部署详解 详细见步骤&#xff1a;大模型d…

PHP 完整表单实例

PHP 完整表单实例 引言 表单是网站与用户交互的重要方式&#xff0c;尤其是在收集用户输入数据时。PHP 作为一种流行的服务器端脚本语言&#xff0c;在处理表单数据方面具有强大的功能。本文将提供一个完整的 PHP 表单实例&#xff0c;涵盖表单创建、数据收集、验证和存储等关…

如何通过Deepseek的API进行开发和使用(适合开发者和小白的学习使用教程)

目录 一,API创建与获取 二,直接进行API的调用 2.1 安装第三方库 2.2 官方支持的接口调用方式 2.3 编写的小tips 2.4 AI助手工具代码 三, 配置方面的说明 3.1 token价格和字符用量 3.2 响应错误码 最近在休息的时候也是一直会刷到关于deepseek,简单使用了一下,发现这…

Spring JDBC模块解析 -深入SqlParameterSource

在前面的博客中&#xff0c;我们探讨了Spring Data Access Module中的主要组件&#xff1a; JdbcTemplate和SimpleJdbcInsert。在这两部分的基础上&#xff0c;我们将继续探讨更详细 的用法&#xff0c;包括如何使用RowMapper和SqlParameterSource等高级主题。 JdbcTemplate …

Vue2常用指令

一、指令基础概念 在 Vue2 里&#xff0c;指令是带有 v- 前缀的特殊属性。它的主要作用是当表达式的值发生变化时&#xff0c;会相应地将某些特殊的行为应用到 DOM 上。简单来说&#xff0c;指令就是 Vue 提供的一种便捷语法&#xff0c;让我们可以更轻松地操作 DOM 和实现业务…