码迷,mamicode.com
首页 > 其他好文 > 详细

Golang---GMP调度策略

时间:2020-06-22 01:07:54      阅读:104      评论:0      收藏:0      [点我收藏+]

标签:表达式   read   class   status   设置   计数   控制结构   hid   closed   

摘要:Go 能很好的支持并发模型,这也是 Go 如此火热的原因,那今天我们来学习 Go 的调度机制。

数据结构

G 结构体

  G 是 goroutine 的缩写,相当于操作系统中的进程控制块,在这里就是 goroutine 的控制结构,是对 goroutine 的抽象,下面是 G 的结构(只列出了部分与调度有关的):

技术图片
//用于保存上下文的 gobuf 结构体
type gobuf struct {
    sp   uintptr  //栈指针,上下文中的 sp 指针
    pc   uintptr  //程序计数器,上下文中的 pc 指针
    g    guintptr //指向当前 g  的指针
    ...
}
//用于表示一个等待链表上的 goroutine
type sudog struct {
    g *g  //阻塞列表上的 G

    next *sudog  //双向链表后指针
    prev *sudog  //双向链表前指针
    elem unsafe.Pointer //该 goroutine 的数据指针

    c        *hchan
    ...
}
基础结构

下面是 G 结构体:

技术图片
type g struct {
    stack       stack           // offset known to runtime/cgo

    m            *m            // current m; offset known to arm liblink
    sched        gobuf         //进程切换时,利用 sched 来保存上下文
    param        unsafe.Pointer // 用于传递参数,睡眠时其它 goroutine 设置 param, 唤醒时此 goroutine 可以获取到
    goid         int64          //goroutine 的 ID号

    lockedm        muintptr  //G 被锁定只能在这个 m 上运行
    gopc           uintptr   //创建这个goroutine 的go 表达式的 pc
    waiting        *sudog    //这个 g 当前正在阻塞的 sudog 结构体
}
G struct

M 结构体

  M 是 machine 的缩写,是对机器的抽象,每个 m 都是对应到一条操作系统的物理线程。M 必须关联了 P 才可以执行 Go 代码,但是当它处理阻塞或者系统调用中时,可以不需要关联 P。

技术图片
type m struct {
    g0      *g     // 带有调度栈的 goroutine(默认开启一个进程的时候会开启一个线程,又称主线程(g0))

    mstartfn      func()   //执行函数体的
    curg          *g       //当前运行的 goroutine
    p             puintptr //为了执行 Go 代码而获取的 p(如果不需要执行 Go 代码(syscall...),可为 nil)
    id            int64    //M 的 ID
    locks         int32
    park          note
    alllink       *m   //用于链接 allm(一个全局变量)
    schedlink     muintptr
    lockedg       guintptr  //某些情况下,goroutine 锁定到当前 m, 而不会到切换到其它 m 中去
    createstack   [32]uintptr // stack that created this thread.

    nextwaitm     muintptr    //期望获取锁的下一个 m

    syscall   libcall        //存储系统调用的参数
}
M struct

P 结构体

  P 是 Processor 的缩写。结构体 P 的加入是为了提高 Go 程序的并发度。一共有 GOMAXPROCS(一般为 CPU 的核数) 个 P, 所有的 P 被组织成一个数组(allp), 在 P 上实现了工作流窃取的调度器。

技术图片
type p struct {
    id          int32
    status      uint32 //P 状态 pidle/prunning/...
    link        puintptr
    schedtick   uint32     // 每次执行 goroutine 调度 +1
    syscalltick uint32     // 每次执行系统调用 +1
    sysmontick  sysmontick // last tick observed by sysmon
    m           muintptr   // 链接到它的 m (nil if idle)
    mcache      *mcache
    pcache      pageCache

    // Queue of runnable goroutines. Accessed without lock.
    // P 执行 Go 代码时,优先从自己这个局部队列中取,这时可以不用加锁,提高了并发度
    // 如果发现这个队列是空,则去其它 P 的队列中拿一半过来,实现工作流窃取的调度,这种情况需要给调度器加锁
    runqhead uint32  //本地 G 队列头
    runqtail uint32  //本地 G 队列尾
    runq     [256]guintptr  //本地 G 队列
    runnext guintptr  //下一个准备好运行的 goroutine

    sudogcache []*sudog
    sudogbuf   [128]*sudog
    ...
}
P struct

全局变量

 

调度策略

源码分析

总结

 

参考文献

 

Golang---GMP调度策略

标签:表达式   read   class   status   设置   计数   控制结构   hid   closed   

原文地址:https://www.cnblogs.com/zpcoding/p/13173866.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!