面试题答案
一键面试G - M - P模型概述
- G(Goroutine)
- 含义:代表一个协程,是Go语言中并发执行的最小单位。每个G都有自己的栈空间、程序计数器以及局部变量等。
- 职责:封装了需要并发执行的任务逻辑,例如一段函数代码。
- M(Machine)
- 含义:代表操作系统线程,它是真正在操作系统层面执行任务的实体。
- 职责:负责执行Goroutine,M会从P的本地运行队列或者全局运行队列中获取G来执行,并负责与操作系统的交互,如系统调用等。
- P(Processor)
- 含义:处理器,它是G和M之间的中间层,用于管理一组G并为M提供执行上下文。P持有一个本地G的运行队列。
- 职责:P负责调度G到M上执行,它决定了哪个G能在哪个M上运行。同时,P还管理着一个本地的G队列,当有新的G创建时,优先放入本地队列,当本地队列满了再放入全局队列。
G - M - P协同工作机制
- G的创建与调度
- 当创建一个新的G时,它会首先被放入创建它的P的本地运行队列中。如果P的本地运行队列已满,G会被放入全局运行队列。
- M会从P的本地运行队列获取G来执行,如果本地队列为空,M会尝试从全局运行队列或者其他P的本地运行队列(通过窃取机制)获取G。
- M与P的关联
- 每个M需要关联一个P才能执行G。在程序启动时,会创建一定数量的P和M,并且将P和M进行绑定。
- 当M执行系统调用等阻塞操作时,P会与M分离,此时P可以被其他空闲的M获取,继续执行本地队列中的G。
- 全局运行队列与本地运行队列交互
- 全局运行队列存储那些无法放入P本地队列的G。M在本地队列空时,会尝试从全局队列获取G,每次获取一定数量(例如1个)的G到本地队列再执行。同时,当P的本地队列负载过高时,也会将部分G迁移到全局队列。
在多核CPU环境下提高调度效率的方式
- 多核并行
- 每个P可以绑定到不同的CPU核心上,使得多个M可以同时在不同核心上执行不同的G,实现真正的并行计算。例如,一个4核CPU的机器,若有4个P,每个P分别绑定到一个核心,4个M可以同时执行4个不同的G,充分利用多核资源。
- 任务窃取
- 在多核环境下,不同P的本地运行队列负载可能不均衡。当一个M执行完本地队列的G后,会从其他P的本地队列窃取一半的G到自己的本地队列,这种机制使得负载高的P能够将任务分担给负载低的P,提高整体的调度效率。
- 减少锁争用
- 由于每个P有自己的本地运行队列,G的调度和执行在本地队列内进行,减少了对全局资源的竞争,特别是减少了对全局运行队列的锁争用。相比单队列调度模型,在多核环境下,G - M - P模型通过这种方式提高了调度的并发性能。