美文网首页
golang协程调度面试总结

golang协程调度面试总结

作者: yuff | 来源:发表于2023-02-13 14:06 被阅读0次

1.go的GMP模型

goroutine运行在用户态,是由runtime来控制调度的,调度过程中主要涉及到三个对象:G-go关键字启动的协程(也有内部启动的协程如g0)、M-运行G的系统线程(由操作系统控制调度)、P-资源处理器,用来管理G的,M必须绑定一个P才能运行其协程队列里的G。具体的调度过程是这样的:
程序启动时创建GOMAXPROCS个P,当有go关键字创建G时会优先加入到当前P的本地队列中(缓存局部性原理),当本地队列满了调度器会调度部分协程到全局队列中,此时P去线程池唤醒一个休眠的M(如没有则新创建一个M)进行绑定,M获取到P本地队列中的G开始执行,当本地队列里面的G执行完则先去全局队列获取,若获取不到则去其它队列偷取,若都没有则当前M进入自旋状态(因为线程的创建销毁唤醒比较消耗CPU,但是自旋线程本质是线程在运行不过没有执行G,因此也有数量限制,超过限制M休眠),不断的循环寻找等待新的G。

2.怎么防止G全局队列饥饿

极端情况下所有本地队列的G被执行数和生产新的G数量保持“平衡”,导致全局队列里的G饥饿无法被执行。go调度器为了公平起见,每执行61次G后会直接去全局队列取1个G。

//go1.18.4/src/runtime/proc.go:3175
// Check the global runnable queue once in a while to ensure fairness.
// Otherwise two goroutines can completely occupy the local runqueue
// by constantly respawning each other.
if _g_.m.p.ptr().schedtick%61 == 0 && sched.runqsize > 0 {
    lock(&sched.lock)
    gp = globrunqget(_g_.m.p.ptr(), 1)
    unlock(&sched.lock)
}

3.G、M、P的个数

  • golang创建协程内存消耗较小(2K左右,理论上个数受内存大小限制),加上G在退出时会把G清理掉后放入本地或者全局空闲列表的gfree队列中以方便复用,配置一般的机器也能开启十万级 goroutine。
  • M线程的个数默认是10000个,线程相较G耗资源,一般达不到该数量,M必须绑定一个P才能执行G,所以M的数量一般大于等于P的数量。
  • P的个数由GOMAXPROCS控制,默认为CPU的核数。

4.go的协程调度策略,具体如何抢占的

进程由操作系统调度,分为抢占式调度和非抢占式调度(FCFS),抢占式调度有先到先得(FIFO)、最短任务优先(SJF)、最短完成时间任务优先(STCF)、时间片轮转(Round-Robin, RR)等策略。操作系统调度策略
协程由runtime在用户态进行调度的,采用时间片算法的方式,公平,可以防止少数协程长时间执行导致其它协程饥饿。
具体的抢占过程是基于信号的方式:程序运行时守护线程sysmon会去监控执行所有G的时间,如果G超过了10ms,sysmon会给当前的M发送一个sigurg信号,M中断执行该G(放入全局队列),去获取新的G;当调用syscall时间太长时也会发送sigurg信号。

5.GMP模型,发生了阻塞怎么办,如何保证G不会被其他G的系统调用、网络调用阻塞

  • M系统线程发生系统调用阻塞
    1.如G打开文件时,M与P解绑并阻塞进入等待状态,G也进入等待状态,此时P唤醒一个M或者创建一个新M继续执行后面的G;
    2.当系统调用结束,M优先和旧P进行绑定继续执行G(亲和性、局部性);如果旧P正在被使用并且有空闲的P,则新P和M绑定,刚才阻塞的G加入其本地队列,M继续执行G;如果没有空闲的P,G加入到全局队列中,等待被其它的P调度,然后M将进入缓存池休眠。
  • G协程阻塞
    1.G读写channel时阻塞:此时MP不解绑(M继续执行后面的G),而G加入到channel的recvq或sendq队列中进行等待,当有数据写channel或有读channel时唤醒对应的G,加入P的本地队列或者全局队列等待执行。
    2.G发起网络请求时阻塞:比如当创建完一个Listener,调用Accept开始接收客户端连接。如果没有对应的请求,那么最终会把G放入到pollDesc的rg;
    如果是一个conn类型的fd等待可写I/O,那么会把G放入到pollDesc的wg中。rg、wg都是指针类型,实际这两个字段存储的就是Go底层的G,更具体点是等待i/O ready的G。

6.协程的状态

相关文章

  • golang协程调度面试总结

    1.go的GMP模型 goroutine运行在用户态,是由runtime来控制调度的,调度过程中主要涉及到三个对象...

  • golang 协程调度

    前言 Goroutine调度是一个很复杂的机制,尽管Go源码中提供了大量的注释,但对其原理没有一个好的理解的情况下...

  • GPM调度模型

    目录 1.什么是进程调度2.并发与并行3.进程、线程与协程4.Golang的调度机制——GPM模型5.总结 1. ...

  • go-ethereum事件机制设计与实现

    总体介绍 以太坊内部有大量协程,协程间的调度驱动通过事件机制来完成;具体实现使用golang的chan机制。主要方...

  • Golang协程调度器

    说在前面 Golang作为Google亲自孵化出来一门现代编程语言,可以说是吸收了众多早期编程语言的优点,又有其自...

  • 【深度知识】Golang协程调度:协程状态

    状态总览 在讲解操作系统进程调度的部分时,几乎所有的书籍都会先列出一张进程的状态迁移图,通过状态图,能很清晰的把进...

  • golang协程调度模式解密

    golang学习笔记 https://github.com/piao100101/coding-with-go[h...

  • [Android] 深入理解Kotlin协程

    Kotlin协程 协程由程序自己创建和调度,不需要操作系统调度,所以协程比线程更加轻量。相比于线程的切换,协程切换...

  • 协程

    协程与线程 线程的调度是由操作系统负责,协程调度是程序自行负责 与线程相比,协程减少了无谓的操作系统切换 协程实际...

  • 浅谈GoLang协程

    GoLang协程 学习golang也有一段时间了,这里讲一下自己对golang协程的使用理解,golang很多人都...

网友评论

      本文标题:golang协程调度面试总结

      本文链接:https://www.haomeiwen.com/subject/apcdkdtx.html