面试题答案
一键面试Go语言中goroutine调度基本概念
- goroutine:Go语言中实现并发的轻量级执行单元,类似线程,但比线程更轻量,创建、销毁和切换的开销都极小。多个goroutine可在同一地址空间并发执行,共享内存,大大简化了并发编程。
调度器模型(M:N模型)
- M:N模型:Go语言调度器采用M:N模型,即多个用户级线程(goroutine,对应N)映射到多个内核级线程(操作系统线程,对应M)上。与传统1:1模型(每个用户级线程对应一个内核级线程)相比,M:N模型能更高效地利用系统资源。在1:1模型中,一个线程阻塞会导致对应的内核线程阻塞,而M:N模型中,某个goroutine阻塞时,调度器可将其他可运行的goroutine调度到其他M上执行,避免整个程序阻塞。
G、M、P在调度过程中的角色
- G(goroutine)
- 定义:代表一个goroutine,包含了执行的函数、调用栈、局部变量等上下文信息。
- 角色:是调度的基本单位,被创建后放入全局或局部的goroutine队列等待调度执行。当一个goroutine阻塞时,调度器会将其从执行状态切换到阻塞状态,并将其他可运行的goroutine调度到M上执行。当阻塞的原因解除(如I/O完成),该goroutine会被重新放入可运行队列等待再次调度。
- M(machine)
- 定义:代表一个内核级线程,由操作系统管理,是真正在CPU上执行代码的实体。
- 角色:负责执行goroutine。每个M都有一个本地的goroutine队列,当M从P的本地队列或全局队列获取到一个可运行的goroutine后,就会在该M上执行这个goroutine。M在执行goroutine过程中,如果遇到系统调用等阻塞操作,会将当前正在执行的goroutine切换出去,自身进入阻塞状态,调度器会调度其他M来执行其他可运行的goroutine。当阻塞操作完成,M会尝试从P的队列中获取新的goroutine继续执行。
- P(processor)
- 定义:代表一个逻辑处理器,它维护了一个本地的goroutine队列,并且关联了一个M,用于管理和调度goroutine到M上执行。
- 角色:它提供了执行goroutine的上下文环境,包括goroutine调度器的运行时状态,如本地goroutine队列等。P的数量可以通过
runtime.GOMAXPROCS
函数设置,它决定了同一时刻最多有多少个M可以并行执行用户代码。P在调度过程中,会优先从自己的本地goroutine队列中获取goroutine给关联的M执行,如果本地队列为空,则会从全局goroutine队列或其他P的本地队列中窃取goroutine,以保证M始终有工作可做。