Go语言中Goroutine CPU核心设置与调度原理
在Go语言开发中,合理配置并发执行的物理核心数对性能至关重要。本文将演示如何使用runtime包中的GOMAXPROCS函数动态或静态地限制/设置程序占用的CPU核数,并通过实验对比不同核数设置下的CPU资源消耗情况。
设置并发运行核数
Go 1.5之后默认将GOMAXPROCS设置为等于CPU逻辑核心数的数量,但在需要精细化控制并发度时,开发者仍需手动干预。这主要涉及两个关键API:
runtime.NumCPU():获取当前操作系统提供的可用CPU逻辑核心总数。runtime.GOMAXPROCS(n int):设置运行时允许同时执行(抢占式调度)的代码的最大CPU数量。注意参数不能为负数且不能超过系统核心数。
第1步:编写模拟高负载并发程序
为了直观观察核心数对CPU的影响,我们构建一个持续自增的死循环函数doSomething()作为工作负载。
func doSomething() {
var i int
for {
i++
}
}
func main() {
cpu := runtime.NumCPU()
fmt.Println("本机cpu核数:", cpu)
fmt.Println("输入模拟的cpu数:")
reader := bufio.NewReader(os.Stdin)
buf, _ := reader.ReadBytes('\n')
cmdStr := (string)(buf)
num, err := strconv.Atoi(strings.Trim(cmdStr, "\r\n"))
if err != nil || num > cpu || num <= 0 {
fmt.Println("输入的数字不正确 err:{0}", err)
return
}
//设置核数
runtime.GOMAXPROCS(num)
for i := 0; i < 10; i++ {
//做个死循环
go doSomething()
}
fmt.Println("程序已经开始执行")
time.Sleep(time.Second * 30)
for j := 5; j > 0; j-- {
fmt.Printf("程序倒计时退出: %ds...\n", j)
time.Sleep(time.Second)
}
fmt.Printf("程序退出")
}该脚本首先读取用户输入的目标CPU核心数,利用runtime.GOMAXPROCS进行设定,随后启动10个并发协程进入无限循环,并在主线程休眠等待期间观察系统状态。
CPU资源占用实测效果
基于8核处理器的设备环境,按照上述代码分别配置1、2、4、8个核心进行并发调度,实际系统资源监控结果如下所示:
图一 未开始运行
图二 运行1个cpu
图三 运行2个cpu
图四 运行4个cpu
图五 运行8个cpu
Goroutine的调度原理复习
理解底层调度机制对于排查并发瓶颈很有帮助。Go语言采用著名的GMP(Goroutine-Machine-Processor)调度模型,其中G代表用户态协程,P代表调度器上下文及本地运行队列,M代表操作系统内核级的工作线程。当我们在代码中改变GOMAXPROCS时,实质上是在调整可以并行持有P(即运行Goroutine)的M的数量,从而影响系统的总吞吐量。若需深入了解其内部协作细节,建议查阅相关的Go并发工作原理进阶资料。
以上就是关于Go语言中Goroutine的CPU设置方式及相关调度的详细内容,更多关于Golang并发编程的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













