1. GMP模型

这里首先给出GMP模型的调度策略. 让大家有一个全局的认识更好

2. G (groutine)

G就是goroutine的意思, 代表了一个协程. 每次go调用的时候,都会创建一个G对象,它包括栈、指令指针以及对于调用goroutines很重要的其它信息,比如阻塞它的任何channel,其主要数据结构:

type g struct {stack       stack   // 描述了真实的栈内存,包括上下界............. // 中间还有很多部分m              *m     // 当前G的绑定的msched          gobuf   // goroutine切换时,用于保存g的上下文      param          unsafe.Pointer // 用于传递参数,睡眠时其他goroutine可以设置param,唤醒时该goroutine可以获取atomicstatus   uint32stackLock      uint32 goid           int64  // goroutine的IDwaitsince      int64 // g被阻塞的大体时间lockedm        *m     // G被锁定只在这个m上运行............. // 省略
}

看这个结构我们可以得知, G需要与M进行绑定. 当然最重要的还是sched这个结构体 存储了调度时g的上下文(context)

type gobuf struct {// 保存CPU的rsp寄存器的值sp   uintptr// 保存CPU的rip寄存器的值pc   uintptr// 记录这个gobuf对象属于那个gg    guintptrctxt unsafe.Pointerret  sys.Uintreglr   uintptrbp   uintptr // for framepointer-enabled architectures
}

sp, pc 寄存器的值, 栈指针等等. 记录了上下文

3. M(machine)

M代表了一个线程 . 每次创建一个M的时候,都会有一个底层线程创建;所有的G任务,最终还是依附于M上执行,其主要数据结构:

type m struct {g0      *g     // 带有调度栈的goroutinegsignal       *g         // 处理信号的goroutinetls           [6]uintptr // thread-local storagemstartfn      func()curg          *g       // 当前运行的goroutinecaughtsig     guintptr p             puintptr // 关联的p和执行的go代码nextp         puintptrid            int32mallocing     int32 // 状态spinning      bool // m是否out of workblocked       bool // m是否被阻塞inwb          bool // m是否在执行写屏蔽
}

其中重点要关注的是 g0 和 curg , curg代表的当前执行的groutine协程

另一个是g0,是带有调度栈的goroutine,这是一个比较特殊的goroutine。普通的goroutine的栈是在堆上分配的可增长的栈,而g0的栈是M对应的线程的栈。所有调度相关的代码,会先切换到该goroutine的栈中再执行。也就是说线程的栈也是用的g实现,而不是使用的OS的。

4. P(processor)

执行器或者处理器. 相当于一个管理者. 每一个M必须要绑定一个P. P自身有一个局部本地队列用来保存g. 并且所有的p都共享这一个全局队列

P负责调度goroutine,维护一个本地goroutine队列,M从P上获得goroutine并执行,同时还负责部分内存的管理。

下面的p的局部实现

lock mutexid          int32status      uint32 // 状态,可以为pidle/prunning/...link        puintptrschedtick   uint32     // 每调度一次加1syscalltick uint32     // 每一次系统调用加1sysmontick  sysmontick m           muintptr   // 关联的mmcache      *mcacheracectx     uintptrgoidcache    uint64 // goroutine的ID的缓存goidcacheend uint64runqhead uint32 // 头部runqtail uint32 // 尾部// 队列在这呢runq     [256]guintptr   // 可运行的goroutine的队列runnext guintptr // 下一个运行的g
}

5.调度顺序


下面说一下详细的过程

  1. go func(){}创建一个新的goroutine
  2. 这个goroutine会被挑选进入一个P的本地队列, 若是本地队列满了, 那么就进入全局的队列
  3. 这时M向P要goroutine去执行了. G依附于M上运行,每个M绑定一个P。如果P的本地队列没有G,M会从全局队列寻找G, 如果全局队列也没有G, 那么P会从其他P里面窃取G
  4. M被操作系统调度到CPU上面执行, G也就执行了, 若是在此期间,M这个线程遇到阻塞或者系统调用, 那么此时P就会与M解绑. 并在M的休眠队列里面唤醒一个新的M与之绑定, 然后再去运行G.
  5. 若是在此期间是G发生了阻塞, 那么M也会阻塞. 此时M就会与P解绑, 由M1接管P.去运行其他的G. M等待阻塞的返回, 就将G放入全局队列中了, 自己就去休眠了.
  6. 运行完之后G就会被销毁退出.

5.1 协程调度

5.1.1 主动调度

主动的让出CPU资源, 此时当前协程切换到g0, 取消G与M之间的绑定关系, 再将此G放入全局队列中, 并调用schedule函数开始新一轮的循环

5.1.2 抢占式调度

当某个协程占用CPU时间过长时, go语言调度器就会强制中断执行.并保存上下文等待下次调度

Go语言线程与协程之间的关系之GMP模型相关推荐

  1. python 协程、进程、线程_Python进程、线程、协程之间的关系

    一.从操作系统角度 操作系统处理任务, 调度单位是 进程 和 线程 . 1.进程: 表示一个程序的执行活动 (打开程序.读写程序数据.关闭程序) 2.线程: 执行某个程序时, 该进程调度的最小执行单位 ...

  2. 进程、线程、协程之间的关系

    一.进程: 是系统进行资源分配和调度的基本单位,是操作系统结构的基础,是程序的实体:每个进程都有它自己的地址空间(文本区域.数据区域.堆栈): 二.线程: 是程序执行流的最小单元,一个标准的线程由线程 ...

  3. python协程和线程_线程和协程之间的区别

    线程和协程之间的区别很大,甚至大过进程和线程之间的区别.线程建立在进程之上,协程建立在线程之上.那么协程是什么呢? 协程是一段计算机程序,它一般是一个协作类型的子程序,执行时允许暂停和恢复.协程非常适 ...

  4. python协程和线程区别_python中的线程和协程之间有什么区别

    一.首先我们来了解一下线程和协程的概念1.线程线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源( ...

  5. 进程、线程和协程之间的区别和联系

    文章目录 一.进程 二.线程 三.进程和线程的区别与联系 四.一个形象的例子解释进程和线程的区别 五.进程/线程之间的亲缘性 六.协程 一.进程   进程,直观点说,保存在硬盘上的程序运行以后,会在内 ...

  6. java协程和线程_Kotlin中的线程和协程之间的区别

    由于我仅在JVM上使用协程,因此我将讨论JVM后端,也有Kotlin本机和Kotlin JavaScript,但是这些Kotlin后端不在我的讨论范围之内. 因此,让我们开始将Kotlin协程与其他语 ...

  7. kotlin 子线程睡3秒_Kotlin中线程和协程之间的区别

    Ruslan.. 47 由于我只在JVM上使用协同程序,我将讨论JVM后端,还有Kotlin Native和Kotlin JavaScript,但Kotlin的这些后端超出了我的范围. 让我们首先将K ...

  8. handler回调主线程_Android使用Handler实现子线程与子线程、子线程与主线程之间通信...

    转载:https://blog.csdn.net/shaoenxiao/article/details/54561753 今天这篇文章只讲一下怎么使用Handler实现子线程与子线程之间.子线程与主线 ...

  9. 请你说说进程、线程、纤程之间的区别?

    其他链接:JAVA相关的深度技术博客链接 相信很多小伙伴们在面试的时候,面试官都会提这样的一个问题. 请你说说什么是进程,什么是线程,两者有什么区别? 很多小伙伴可能会直接说,进程就是一个个后台程序, ...

最新文章

  1. JavaScript 二进制的 AST
  2. Windows原生运行Linux的技术细节
  3. c++ 使用vs2010调用 win32api
  4. 数据挖掘流程(二):数据预处理
  5. sprint周期总结
  6. 男程序员怎么保养皮肤【护肤】?
  7. IOS 本地推送 IOS10.0以上 static的作用 const的作用
  8. 百度十亿级流量的搜索前端,是怎么做架构升级的?
  9. 代码提交本地代码和远程代码不同步问题(笔记)
  10. EMD算法原理分解信号
  11. java.lang.IllegalStateException: Ambiguous mapping found. Cannot map ' ' bean method
  12. 解读制造业数字化转型的现状及发展趋势
  13. java 格式化日期(DateFormat)
  14. java语言开发的中间件名称,值得收藏!
  15. 三步完美完成wordpress外链跳转
  16. ubuntu如何查看java版本_Ubuntu 如何查看安装的 JDK
  17. 鸿蒙试炼多少可以单挑,知己知彼《灭神》单挑虚无之地大BOSS
  18. java ssl 双向认证_Java实现SSL双向认证的方法
  19. JS代码:身份证号EMAIL检验
  20. There is no getter/setter for property named ‘XXX‘ in ‘class com.XXX‘

热门文章

  1. DataLoader 与 Dataset
  2. 机器学习笔记:logistic regression
  3. tableau可视化数据分析60讲(十四)-tableau可视化视图(交叉表项目符号图)
  4. Python的lambda匿名函数
  5. linux 下Eclipse的安装
  6. 机器学习算法与Python实践之(三)支持向量机(SVM)进阶
  7. matlab 0000,部分结果出现虚数单位 0.0000i
  8. 深度学习100例-生成对抗网络(DCGAN)生成动漫人物 | 第20天
  9. QT中利用Qlabel显示当前的时间:年-月-日-时-分-秒-星期
  10. 数据结构与算法基础--错题集