设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间01 现在时间01 缓存数据 当你走完一段之后回头看,你会发现,那些真正能被记得的事真的是没有多少,真正无法忘记的人屈指可数,真正有趣的日子不过是那么一些,而真正需要害怕的也是寥寥无几。

当你走完一段之后回头看,你会发现,那些真正能被记得的事真的是没有多少,真正无法忘记的人屈指可数,真正有趣的日子不过是那么一些,而真正需要害怕的也是寥寥无几。

查看: 389|回复: 0

Go学习记录之runtime包深入解析

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:204
  • 打卡月天数:0
  • 打卡总奖励:3120
  • 最近打卡:2023-08-27 04:26:40
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
379
主题
356
精华
0
金钱
4248
积分
765
注册时间
2022-12-23
最后登录
2025-9-8

发表于 2025-9-8 07:13:56 | 显示全部楼层 |阅读模式
前言:

先前学习到goroutine协程与channel调节并发同步时,有涉及到关于runtime包管理goroutine运行时的知识点。由于没有接触过,并且出于goroutine的重要性(runtime听着很高大上)的原因,通过多方学习并博客记录。

一、runtime包内容学习


1、作用:

其作用主要是与程序的运行时环境进行交互,提供了一系列函数和变量,用于控制、管理和监视程序的执行:

① Goroutine和并发控制:

runtime包提供了一些函数来管理goroutine,如创建和销毁goroutine、设置最大可同时执行的CPU数目等,以及用于并发控制的函数,如让出CPU时间片、锁定和解锁goroutine到线程等。
  1. package main

  2. import (
  3.     "fmt"
  4.     "runtime"
  5.     "time"
  6. )

  7. func worker() {
  8.     defer fmt.Println("Worker exiting")
  9.     runtime.Gosched() // 主动让出 CPU
  10.     fmt.Println("Worker running")
  11. }

  12. func main() {
  13.     go worker()
  14.     time.Sleep(time.Second)
  15.     fmt.Println("Number of goroutines:", runtime.NumGoroutine())
  16. }
复制代码

② 垃圾回收:

Go语言使用自动垃圾回收机制来管理内存,runtime包提供了手动触发垃圾回收、设置垃圾回收的百分比、获取内存统计信息等函数,用于对垃圾回收进行调控和监测。
  1. func main() {
  2.     var m runtime.MemStats
  3.     runtime.ReadMemStats(&m)
  4.     fmt.Printf("Allocated memory: %d bytes\n", m.Alloc)
  5.     runtime.GC() // 手动触发 GC
  6.     runtime.ReadMemStats(&m)
  7.     fmt.Printf("After GC: %d bytes\n", m.Alloc)
  8. }
复制代码
③ 栈和堆操作:

runtime包提供了函数来获取当前goroutine的堆栈信息、完整的堆栈跟踪,以及对堆栈进行分析和剖析的相关函数。

④ 系统信息和调试:

runtime包提供了获取CPU核心数、CPU性能分析、调试信息等函数,可以用于获取关于系统的一些基本信息和进行程序的调试。

⑤ 错误处理:

runtime包提供了获取调用栈信息、根据PC地址获取函数信息等函数,用于错误处理和调试时追踪错误发生的位置。
  1. func printStack() {
  2.     var buf [4096]byte
  3.     n := runtime.Stack(buf[:], false)
  4.     fmt.Printf("Stack trace:\n%s\n", string(buf[:n]))
  5. }

  6. func main() {
  7.     defer printStack()
  8.     panic("Something went wrong!")
  9. }
复制代码
⑥ P操作:

runtime包提供了与处理器(P)的相关操作,如获取可同时执行的最大P数目、绑定goroutine到特定的P等。

⑦ 信号处理:

runtime包提供了处理C语言信号的函数,用于和外部C库进行交互时的信号处理。
通过使用runtime包提供的函数和变量,可以更控制程序的运行时行为、优化性能、处理错误和调试问题。但需要注意,对runtime包过度依赖可能会降低代码的可移植性

2、相关函数:

runtime包提供了与程序运行时环境交互的函数和变量,包含了与上述作用相关的函数:

① Goroutine相关:
  1. goexit():终止当前goroutine的执行。GOMAXPROCS(n int):设置可同时执行的最大CPU数。NumGoroutine():返回当前存在的goroutine数目。
复制代码
② 垃圾回收:
  1. GC(): 手动触发垃圾回收。SetFinalizer(obj interface{}, finalizer interface{}):为对象设置一个垃圾回收的终结器(finalizer),当对象被垃圾回收时,终结器会被调用。
复制代码
③ 栈:
  1. Stack(buf []byte, all bool): 返回当前goroutine的堆栈信息。StackTrace(p *Profiling)::返回当前程序的完整堆栈跟踪。
复制代码
④ 内存统计:
  1. ReadMemStats(m *MemStats): 获取当前程序的内存使用统计信息。
复制代码
⑤ 并发控制:
  1. LockOSThread(): 锁定当前goroutine到当前线程上。UnlockOSThread(): 解除当前goroutine对当前线程的锁定。
  2. (等)
复制代码
同样的,由于其对底层进行交互,过多使用相关函数也会降低可移植性,开发过程中需要注意。

3、几个较为重要的函数:


① runtime.Gosched():让出CPU时间片,重新等待安排任务
  1. package main

  2. import (
  3.     "fmt"
  4.     "runtime"
  5. )

  6. func main() {
  7.     go func(s string) {
  8.         for i := 0; i < 2; i++ {
  9.             fmt.Println(s)
  10.         }
  11.     }("world")
  12.     // 主协程
  13.     for i := 0; i < 2; i++ {
  14.         // 切一下,再次分配任务
  15.         runtime.Gosched()
  16.         fmt.Println("hello")
  17.     }
  18. }
复制代码
② runtime.Goexit():退出当前协程
  1. package main

  2. import (
  3.     "fmt"
  4.     "runtime"
  5. )

  6. func main() {
  7.     go func() {
  8.         defer fmt.Println("A.defer")
  9.         func() {
  10.             defer fmt.Println("B.defer")
  11.             // 结束协程
  12.             runtime.Goexit()
  13.             defer fmt.Println("C.defer")
  14.             fmt.Println("B")
  15.         }()
  16.         fmt.Println("A")
  17.     }()
  18.     for {
  19.     }
  20. }
复制代码
③ runtime.GOMAXPROCS:

Go运行时的调度器使用GOMAXPROCS参数来确定需要使用多少个OS线程来同时执行Go代码。默认值是机器上的CPU核心数。例如在一个8核心的机器上,调度器会把Go代码同时调度到8个OS线程上(GOMAXPROCS是m:n调度中的n)。
Go语言中可以通过runtime.GOMAXPROCS()函数设置当前程序并发时占用的CPU逻辑核心数。
  1. Go1.5版本之前,默认使用的是单核心执行。Go1.5版本之后,默认使用全部的CPU逻辑核心数。
复制代码
可以通过将任务分配到不同的CPU逻辑核心上实现并行的效果
  1. func a() {
  2.     for i := 1; i < 10; i++ {
  3.         fmt.Println("A:", i)
  4.     }
  5. }

  6. func b() {
  7.     for i := 1; i < 10; i++ {
  8.         fmt.Println("B:", i)
  9.     }
  10. }

  11. func main() {
  12.     runtime.GOMAXPROCS(1)
  13.     go a()
  14.     go b()
  15.     time.Sleep(time.Second)
  16. }
复制代码
两个任务只有一个逻辑核心,此时是做完一个任务再做另一个任务。 将逻辑核心数设为2,此时两个任务并行执行,代码如下。
  1. func a() {
  2.     for i := 1; i < 10; i++ {
  3.         fmt.Println("A:", i)
  4.     }
  5. }

  6. func b() {
  7.     for i := 1; i < 10; i++ {
  8.         fmt.Println("B:", i)
  9.     }
  10. }

  11. func main() {
  12.     runtime.GOMAXPROCS(2)
  13.     go a()
  14.     go b()
  15.     time.Sleep(time.Second)
  16. }
复制代码
二、底层设计:
  1. Go语言的高效与简洁,离不开其运行时环境。runtime包作为Go语言运行时系统的核心接口,承载着内存管理、协程调度、垃圾回收、类型信息处理等关键功能。深入理解runtime包的底层设计,可以深入了解Go语言的运行机制。
复制代码
1、内存管理与垃圾回收的底层协作


① 内存分配策略

runtime包中的内存分配器采用分层设计,分为线程缓存(Thread Cache)、中心缓存(Central Cache)和堆(Heap)三个层级:
  1. • 线程缓存:每个Go线程拥有独立的线程缓存,用于快速分配小对象(通常小于16字节),避免频繁访问全局资源,减少锁竞争;
  2. • 中心缓存:作为线程缓存的补充,负责从堆中获取大块内存,并切割成适合线程缓存的小块,平衡各线程间的内存使用;
  3. • 堆:内存分配的最终来源,由垃圾回收器统一管理,当线程缓存和中心缓存无法满足需求时,直接从堆中分配内存 。
复制代码
② 垃圾回收协同工作

垃圾回收器(GC)与内存分配器紧密配合,runtime包通过一系列函数控制GC的行为,如runtime.GC()可手动触发垃圾回收。在GC过程中:
  1. • 标记阶段:从根对象(如全局变量、栈上变量)出发,标记所有可达对象;
  2. • 清除阶段:回收未被标记的对象,将其占用的内存归还到空闲列表;
  3. • 整理阶段(可选):在特定情况下,对堆内存进行整理,减少内存碎片 。
复制代码
2、协程调度的底层实现细节

runtime包是协程调度的核心执行者,基于M:N调度模型实现高效的协程调度:
  1. • Goroutine(G):用户态的轻量级线程,是Go语言并发的基本单元;
  2. • Machine(M):对应操作系统线程,负责执行Goroutine中的代码;
  3. • Processor(P):协程调度的关键组件,维护本地协程队列,绑定到M上以减少上下文切换开销。
复制代码
调度过程中,runtime包通过以下机制确保协程高效运行:
  1. • 本地队列优先:P优先从本地队列获取Goroutine执行,减少竞争;
  2. • 工作窃取算法:当本地队列为空时,P从其他P的本地队列窃取Goroutine,均衡负载;
  3. • 阻塞处理:当M执行的Goroutine发生阻塞(如I/O操作),M与P分离,P绑定到其他空闲M继续执行其他Goroutine,避免线程浪费 。
复制代码
3、运行时类型信息与反射支持

runtime包管理着程序中所有类型的元数据,这些信息是反射功能的基础:
  1. • 类型描述:通过结构体记录类型的大小、对齐方式、方法集合等信息,如rtype结构体存储类型的基本属性,itab结构体记录接口类型与具体实现类型的映射关系;
  2. • 反射实现:reflect包依赖runtime包提供的类型信息,在运行时动态获取对象的类型、调用方法、修改属性 。
复制代码
例如,在进行反射操作时,runtime包负责提供类型比较、方法查找等底层支持,确保反射操作的正确性和高效性。

4、runtime包与开发者实践

虽然runtime包的大部分功能在幕后自动运行,但开发者在某些场景下仍需关注其行为:
  1. • 性能调优:通过runtime.GOMAXPROCS()设置处理器数量,优化协程调度效率;利用runtime/pprof包进行性能分析,定位内存泄漏、CPU瓶颈等问题;
  2. • 特殊场景处理:在需要与操作系统深度交互时,使用runtime包提供的系统调用接口;在编写高性能程序时,通过runtime包的内存分配函数手动管理内存 。
复制代码
总结

到此这篇关于Go学习记录之runtime包深入解析的文章就介绍到这了,更多相关Go runtime包内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表