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

GO_并发编程---Goroutine

一、前言:Go 语言的核心优势 —— 原生并发

Go 被称为21 世纪的 C 语言,两大核心亮点:

  1. 语法设计简洁、上手门槛低
  2. 语言层面原生支持并发,内置 GC 自动垃圾回收,无需手动管理内存

Go 并发设计哲学

不同于传统多线程靠实现同步,Go 采用通信的方式解决并发竞争:

不要通过共享内存来通信,而要通过通信来共享内存

二、基础概念:并发 vs 并行

1. 并行(Parallelism)

同一时刻,多条指令在不同 CPU 核心同时执行,必须依赖多核硬件。

2. 并发(Concurrency)

同一时刻只有一条指令在 CPU 执行,系统通过时间片轮转快速切换多个任务;宏观看起来多个任务同时运行,微观是交替执行,单核 CPU 即可实现。

举例:单核 CPU 处理 3 个 1s 任务,靠时间片切换实现并发,在有限硬件资源下提升整体处理效率。

核心区分总结

  • 并发:同时处理多件事(单核、任务切换)
  • 并行:同时做多件事(多核、真正同时执行)

三、Goroutine(协程):Go 并发核心

1. 什么是 Goroutine

Goroutine 是 Go 内置的轻量级协程,可简单理解为轻量任务,是 Go 并行调度的核心:

  • 比操作系统线程体积更小、开销极低;
  • 底层采用 M:N 调度:成千上万个 goroutine 会复用少量 OS 线程;
  • Go 运行时自动管理 goroutine 内存共享,调度成本远低于线程;
  • 优势:易用、高效、资源占用极少。

2. 创建 Goroutine

语法:在函数 / 匿名函数前加go关键字,即可新建子协程。

go

// 普通函数开启协程 go newTask() // 匿名函数协程(必须加()执行) go func() { // 协程业务逻辑 }()

3. 核心规则:主协程退出,所有子协程直接销毁

main函数本身是主协程,一旦 main 执行完毕,整个进程直接终止,所有未执行完成的子协程会被强制杀死,不会等待。

示例 1:子协程来不及执行

go

package main import "time" func newTask() { for { fmt.Println("子协程运行中") time.Sleep(time.Second) } } func main() { // 开启子协程 go newTask() // 主协程循环2次就退出 i := 0 for { i++ fmt.Println("主协程 i = ", i) time.Sleep(time.Second) if i == 2 { break // main结束,子协程直接销毁,无任何输出 } } }
示例 2:死循环阻塞主协程(测试用)

写无限for{}阻塞主协程,防止程序提前退出,方便观察子协程输出:

go

func main() { go newTask() // 死循环阻塞主线程 for {} }

四、runtime 包:协程调度控制工具

1. runtime.Gosched ():主动让出 CPU 时间片

作用:当前 goroutine 主动放弃执行权,调度器切换其他就绪协程运行,等其他协程执行完毕后再切回当前协程。

示例:不加 Gosched 时,主协程会优先跑完,子协程无执行机会

go

package main import ( "fmt" "runtime" ) func main() { go func() { for i := 0; i < 5; i++ { fmt.Println("子协程 go") } }() for i := 0; i < 2; i++ { fmt.Println("主协程 hello") runtime.Gosched() // 主动让出时间片,让子协程先执行 } }

2. runtime.Goexit ():终止当前协程

作用:立即结束当前所在 goroutine,不会影响其他协程;会优先执行当前协程所有 defer 延迟函数,普通return仅终止当前函数,不会退出协程。

go

package main import ( "fmt" "runtime" ) func test() { defer fmt.Println("执行defer延迟语句") // runtime.Goexit() // 终止整个子协程 return // 仅退出test函数,协程继续往下执行 fmt.Println("该行永远不会打印") } func main() { go func() { fmt.Println("子协程开始") test() fmt.Println("子协程结束") // Goexit()时该行不会执行 }() // 死循环阻塞主协程 for {} }

3. runtime.GOMAXPROCS (n):设置并行 CPU 核心上限

  • 功能:设置可并行执行 goroutine 的 OS 线程最大数量,返回修改前的旧值;
  • 规则:
    1. n=1:单核运行,无真正并行,仅时间片切换并发;
    2. n 等于 CPU 物理核数:最大化多核并行能力;
    3. Go1.5 + 默认值为机器 CPU 核心数;
  • 效果:核数越大,多协程交替输出越混乱,并行效率越高。

go

package main import ( "fmt" "runtime" ) func main() { // 设置仅使用1核CPU,返回旧配置 old := runtime.GOMAXPROCS(1) fmt.Println("修改前CPU并行数:", old) for { go fmt.Print(1) fmt.Print(0) } }

五、多协程资源竞争问题

场景模拟:多个协程共用同一个打印机(公共资源)

多个 goroutine 同时操作同一共享资源,会出现输出错乱、数据混乱,即并发竞争,需要同步机制解决。

go

package main import "fmt" // 公共打印机资源 func Printer(str string) { for _, data := range str { fmt.Print(string(data)) } fmt.Println() } func person1() { Printer("hello") } func person2() { Printer("world") } func main() { // 两个协程同时抢占打印机,输出错乱 go person1() go person2() // 阻塞主协程观察效果 for {} }

解决方案预告

Go 官方推荐使用channel 通道实现 goroutine 同步与通信,解决资源竞争,下一章详细讲解。

六、全文总结(面试 / 复习速记)

  1. Go 核心优势:语言原生并发,goroutine 轻量高效,GC 自动回收;
  2. 并发:单核时间片切换;并行:多核同时执行;
  3. goroutine 创建:go + 函数,主协程退出则所有子协程销毁;
  4. runtime 三大工具:
    • Gosched():主动让出 CPU;
    • Goexit():终止当前协程,执行 defer;
    • GOMAXPROCS():控制并行 CPU 核心数;
  5. 多协程访问公共资源会产生竞争,使用 channel 通信实现同步。
http://www.cnnetsun.cn/news/3541586.html

相关文章:

  • C语言自增运算符深度解析:从原理到指针应用与避坑指南
  • WorthBase(家底)技术架构全解析:一款本地优先的个人财务 App
  • docker compose端口暴露才能外界访问(https为例子)
  • Drain3性能优化实践:内存控制与LRU缓存策略深度调优
  • Powerlevel10k:让你的终端从黑白到彩虹的魔法配置指南
  • MCSManager完整指南:5分钟快速搭建专业游戏服务器集群
  • 计算机毕业设计之新能源汽车电池回收处理平台设计与实现
  • Node.js 极简安装指南(Mac / Windows / Linux 通用,含国内镜像)
  • 一键盘点智能管理,办公室固定资产效益提升全指南
  • 生产级机器学习系统:从模型部署到可信决策的工程实践
  • Windows系统文件dpapi.dll丢失找不到问题解决
  • Nacos服务发现与配置管理核心架构与实践指南
  • AI翻唱工具怎么选?适合换声线、修音与和声的人声处理工具
  • AI模型准确率虚高?别急调参!先排查这7类数据陷阱(含Python检测脚本)
  • ArLazyPreload实战教程:从零开始构建高性能Rails应用
  • ESLint Plugin Cypress:Cypress测试代码质量保证的终极指南
  • 开源BMS修复工具技术解析:基于Arduino的电池管理系统诊断与解锁方案
  • 企业级Agent的“自主性”到底也不知到底有多强?实测告诉你 —— 深度拆解端到端智能自动化的核心指标
  • 超星学习通自动签到终极指南:5分钟实现全自动智能签到
  • 如何用RVC WebUI实现专业级语音克隆?从零到精通的完整技术指南
  • lottie-web动画渲染架构深度解析:从AE到Web原生渲染的技术实现
  • DC-CM588主板同时接二片20T的RK1828算力棒和并行推理方法
  • 最小可运行示例:用火车票识别API提取13个票据字段
  • fakeLoader.js源码解析:深入理解jQuery插件架构与动画实现
  • javaagent-lineage-flink:基于 Java Agent 的 Flink 作业级血缘采集工具
  • 5步掌握SGLang多模态AI处理:从图像理解到视频分析实战指南
  • ddpo-pytorch核心功能解析:prompt_fn与reward_fn如何塑造生成式AI的创造力
  • 小程序毕设项目:用户行为驱动的智能音乐推荐系统实现 在线音乐资源聚合与智能推荐管理系统 (源码+文档,讲解、调试运行,定制等)
  • 电科网安保序加密检索技术解析与应用
  • MusicFreeDesktop:打造你的专属音乐空间,插件化播放器终极指南