MST

星途 面试题库

面试题:Go中goroutine调度的基本原理是什么

请阐述Go语言中goroutine调度的基本概念、调度器模型(如M:N模型),以及G、M、P三者在调度过程中分别扮演的角色。
10.2万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

Go语言中goroutine调度基本概念

  1. goroutine:Go语言中实现并发的轻量级执行单元,类似线程,但比线程更轻量,创建、销毁和切换的开销都极小。多个goroutine可在同一地址空间并发执行,共享内存,大大简化了并发编程。

调度器模型(M:N模型)

  1. M:N模型:Go语言调度器采用M:N模型,即多个用户级线程(goroutine,对应N)映射到多个内核级线程(操作系统线程,对应M)上。与传统1:1模型(每个用户级线程对应一个内核级线程)相比,M:N模型能更高效地利用系统资源。在1:1模型中,一个线程阻塞会导致对应的内核线程阻塞,而M:N模型中,某个goroutine阻塞时,调度器可将其他可运行的goroutine调度到其他M上执行,避免整个程序阻塞。

G、M、P在调度过程中的角色

  1. G(goroutine)
    • 定义:代表一个goroutine,包含了执行的函数、调用栈、局部变量等上下文信息。
    • 角色:是调度的基本单位,被创建后放入全局或局部的goroutine队列等待调度执行。当一个goroutine阻塞时,调度器会将其从执行状态切换到阻塞状态,并将其他可运行的goroutine调度到M上执行。当阻塞的原因解除(如I/O完成),该goroutine会被重新放入可运行队列等待再次调度。
  2. M(machine)
    • 定义:代表一个内核级线程,由操作系统管理,是真正在CPU上执行代码的实体。
    • 角色:负责执行goroutine。每个M都有一个本地的goroutine队列,当M从P的本地队列或全局队列获取到一个可运行的goroutine后,就会在该M上执行这个goroutine。M在执行goroutine过程中,如果遇到系统调用等阻塞操作,会将当前正在执行的goroutine切换出去,自身进入阻塞状态,调度器会调度其他M来执行其他可运行的goroutine。当阻塞操作完成,M会尝试从P的队列中获取新的goroutine继续执行。
  3. P(processor)
    • 定义:代表一个逻辑处理器,它维护了一个本地的goroutine队列,并且关联了一个M,用于管理和调度goroutine到M上执行。
    • 角色:它提供了执行goroutine的上下文环境,包括goroutine调度器的运行时状态,如本地goroutine队列等。P的数量可以通过runtime.GOMAXPROCS函数设置,它决定了同一时刻最多有多少个M可以并行执行用户代码。P在调度过程中,会优先从自己的本地goroutine队列中获取goroutine给关联的M执行,如果本地队列为空,则会从全局goroutine队列或其他P的本地队列中窃取goroutine,以保证M始终有工作可做。