Go语言基础之runtime包
文章引用自
Golang中runtime的使用
runtime调度器是非常有用的东西,关于runtime包几个方法:
-
Gosched:让当前线程让出cpu以让其他线程运行,它不会挂起当前线程,因此当前线程未来会继续执行
-
NumCPU:返回当前系统的CPU核数量
-
GOMAXPROCS:设置最大的可同时使用的CPU核数
-
Goexit:退出当前goroutine(但是defer语句会照常执行)
-
NumGoroutine:返回真该执行和排队的任务总数
-
GOOS:目标操作系统
- GOROOT:返回本机的GO路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package main import "fmt" import "runtime" func main() { fmt.Println( "cpus:" , runtime.NumCPU()) // 返回当前系统的CPU核数量 fmt.Println( "goroot:" , runtime.GOROOT()) // fmt.Println( "NumGoroutine:" , runtime.NumGoroutine()) // 返回真该执行和排队的任务总数 fmt.Println( "archive:" , runtime.GOOS) // 目标操作系统 } 运行结果 cpus: 12 goroot: /usr/local/ go NumGoroutine: 1 archive: darwin |
GOMAXPROCS
// 修改最大可同时使用CPU核数
Golang默认所有任务都运行在一个cpu核里,如果要在goroutine中使用多核,可以使用runtime.GOMAXPROCS函数修改,当参数小于1时使用默认值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package main import "fmt" import "runtime" import "time" func init(){ runtime.GOMAXPROCS(4) // 修改最大可同时使用CPU核数 } func main(){ t := time.Now().Nanosecond() for i:=0;i<100000;i++{ fmt.Println(i*i*i*i) } t2 := time.Now().Nanosecond() fmt.Println(t2-t) } |
Gosched
// 让当前线程让出cpu以让其他线程运行,它不会挂起当前线程,因此当前线程未来会继续执行
这个函数的作用是让当前goroutine让出CPU,当一个goroutine发生阻塞,Go会自动地把与该goroutine出于同一系统线程的其他goroutine转移到另一个系统线程上去,使得这些goroutine不阻塞。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package main import ( "fmt" "runtime" ) func init() { runtime.GOMAXPROCS(1) //使用单核 } func main() { exit := make( chan int) go func () { defer close(exit) go func () { fmt.Println( "b" ) }() }() for i := 0; i < 4; i++ { fmt.Println( "a:" , i) if i == 1 { runtime.Gosched() //切换任务 } } <-exit } |
在windows系统上,结果为:
1 2 3 4 | a: 0 a: 1 a: 2 a: 3 |
切换成多核,每次运行的结果都不一样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | package main import ( "fmt" "runtime" ) func main() { runtime.GOMAXPROCS(4) exit := make( chan int) go func () { defer close(exit) go func () { fmt.Println( "b" ) }() }() for i := 0; i < 10; i++ { fmt.Println( "a:" , i) if i == 4 { runtime.Gosched() //切换任务 } } <-exit } |
总结:多核比较适合那种CPU密集型程序,如果是IO密集型使用多核会增加CPU切换的成本。
GOMAXPROCS和sync配合使用
sync.WaitGroup只有三个方法,Add(),Done()和Wait()。其中Done()是Add(-1)的别名。简单来说,使用Add()添加计数,Done()减少一个计数,计数不为0,阻塞Wait()的运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package main import ( "runtime" "sync" "fmt" ) func main(){ runtime.GOMAXPROCS(2) var wg sync.WaitGroup wg.Add(2) fmt.Printf( "Starting go routines" ) go func (){ defer wg.Done() for char := 'a' ;char< 'a' +26;char++{ fmt.Printf( "%c" ,char) } }() go func () { defer wg.Done() for number := 1;number<27;number++{ fmt.Printf( "%d" ,number) } }() fmt.Println( "\nWaiting to finish" ) wg.Wait() fmt.Println( "\n terminating program" ) } |
运行结果:
1 2 3 4 | Starting go routines Waiting to finish 1234567891011121314151617181920212223242526abcdefghijklmnopqrstuvwxyz terminating program |
总结:首先是wg.Add(2)计数为2,阻塞wg.Wait()的运行,然后是wg.Done()减少计数到0,放开wg.Wait()的运行。
runtime.Caller
Caller 方法反应的是堆栈信息中某堆栈帧所在文件的绝对路径和语句所在文件的行数。而 skip 表示的是从下往上数第几个堆栈帧。如果要打印全部堆栈信息可以直接使用 debug.PrintStack()
来实现。
func Caller(skip int) (pc uintptr, file string, line int, ok bool)
参数:skip是要提升的堆栈帧数,0-当前函数,1-上一层函数,....
返回值:
pc是uintptr这个返回的是函数指针
file是函数所在文件名目录
line所在行号
ok 是否可以获取到信息
示例:
我们分别打印skip为0-3的相关信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | package main import ( "fmt" "runtime" ) func main() { for i := 0 ; i< 4; i++ { test(i) } } func test(skip int) { call(skip) } func call(skip int) { pc,file,line,ok := runtime.Caller(skip) pcName := runtime.FuncForPC(pc).Name() //获取函数名 fmt.Println(fmt.Sprintf( "%v %s %d %t %s" ,pc,file,line,ok,pcName)) |
返回
1 2 3 4 | 17412399 /Users/songzhibin/ go /src/Songzhibin/study/3. go 19 true main.call 17412303 /Users/songzhibin/ go /src/Songzhibin/study/3. go 15 true main.test 17412294 /Users/songzhibin/ go /src/Songzhibin/study/3. go 10 true main.main 16953069 /usr/local/ go /src/runtime/proc. go 203 true runtime.main |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)