3

理解GPM

Go语言的scheduler的实现原理

Go语言中支撑整个scheduler实现的主要有四个结构,分别是G、P、M、Sched,前三个定义在runrtime.h,Sched定义在proc.c中。

  • Sched结构就是调度器,维护了存储M和G的队列,以及调度器的一切状态信息
  • G是goroutine实现的核心结构,是对一个要并发执行的任务的封装,可以称作为用户态的线程,属于用户级资源,对操作系统透明,轻量级,可以大量创建,上下文的切换成本低。
  • P是Processor,逻辑处理器,主要作用是管理G对象,并为G在M上的运行提供本地化资源,他维护了一个goroutine队列runqueue,也可以理解为goroutine的上下文环境。
  • M是Machine,是利用系统调用创建出来的操作系统线程实体,作用是执行G中的并发任务,代表了一个内核线程,由操作系统管理,goroutine就是运行在M上的,M中维护了小对象内存mcache,当前执行的goroutine,随机数发生器等信息。

runtime包

runtime类似于Java或者.Net中的虚拟机,负责内存分配,垃圾回收,goroutine,chanel,切片,map,反射等等。

runtime包的常用函数

package main

import (
    "fmt"
    "runtime"
)

func main() {
    //获取goroot目录
    fmt.Println("GOROOT: ", runtime.GOROOT())
    //获取操作系统
    fmt.Println("os/platform: ", runtime.GOOS)
    //获取当前逻辑cpu的数量,当然也可以用runtime.GOMAXPROCS()手动设置逻辑CPU的数量,不过GO1.8之后不用设置,默认运行在多核
    fmt.Println("逻辑cpu的数量: ", runtime.NumCPU())
    //GOsched: 让当前的额goroutine让出当前的时间片,当一个goroutine发生阻塞的时候,go会把所有和这个阻塞goroutine处于
    //同一个系统线程中的其他goroutine移植到其他系统线程上从而使之不被阻塞。
    go func() {
        for i := 0; i < 3; i++ {
            fmt.Println("goproutine")
        }
    }()
    for i := 0; i < 3; i++ {
        //让出时间片,让其他goroutine先执行
        runtime.Gosched()
        fmt.Println("...........................main")
    }
}
package main

import (
    "fmt"
    "runtime"
    "time"
)

func main() {

    go func() {
        fmt.Println("goroutine开始")
        //调用fun
        fun()
        fmt.Println("goroutine结束")
    }()
    //为了主程序不结束 我们让他睡一会
    time.Sleep(3 * time.Second)
}

func fun() {
    defer fmt.Println("defer job")
    runtime.Goexit() //终止当前的goroutine
    fmt.Println("fun函数")
}

其他还有很多,用到的时候可以查看官方文档:https://golang.google.cn/pkg/

参考资料:bilibili


LiberHome
409 声望1.1k 粉丝

有问题 欢迎发邮件 📩 liberhome@163.com