MST

星途 面试题库

面试题:Go调度器与操作系统线程的关系

请阐述Go调度器中的M(操作系统线程)、G(goroutine)和P(处理器)模型,以及它们如何与操作系统线程相互协作来实现高效的并发处理。并举例说明在什么情况下,Go调度器会创建新的M与操作系统线程关联。
39.7万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

M(操作系统线程)

  • M代表操作系统线程,它是Go调度器与操作系统之间的桥梁。每个M都对应一个操作系统线程,负责执行实际的CPU指令。M可以运行一个或多个G,但是在同一时刻,一个M只能运行一个G。

G(goroutine)

  • G是Go语言中的轻量级线程,即协程。它非常轻量,创建和销毁的开销极小。G包含了执行的代码逻辑、栈空间以及一些调度相关的信息。多个G可以复用一个M,由Go调度器负责在不同的G之间进行切换,实现并发执行。

P(处理器)

  • P代表处理器上下文,它维护了一个本地的G队列。P的数量决定了同一时刻可以并发执行的G的数量,默认情况下,P的数量等于CPU的核心数。P的存在解耦了M和G,使得调度器可以更灵活地将G分配到不同的M上执行。

与操作系统线程的协作

  1. M与操作系统线程:每个M都绑定一个操作系统线程,M负责将分配到它上面的G调度到对应的操作系统线程上执行。
  2. P的作用:P提供了一个执行环境,M从P的本地G队列或者全局G队列中获取G来执行。P还负责管理一些与调度相关的状态,比如当前正在执行的G等。
  3. 调度流程:当一个G被创建时,它会被放入全局G队列或者某个P的本地G队列中。M在运行过程中,会首先尝试从其关联的P的本地G队列中获取G来执行,如果本地队列为空,则会尝试从全局G队列或者其他P的本地G队列中偷取G来执行。

创建新M与操作系统线程关联的情况

  1. G阻塞时:当一个M上运行的G执行系统调用(如I/O操作)而阻塞时,该M会被阻塞,但调度器为了不浪费CPU资源,会创建一个新的M,并将P绑定到这个新的M上,继续执行其他G。例如,当一个G执行net.Dial进行网络连接时,如果连接尚未建立,这个G会阻塞当前的M。此时,调度器会创建新的M,使得其他G可以继续在CPU上执行。
  2. G数量过多时:如果全局G队列和所有P的本地G队列中积累了大量的G,并且现有M的数量不足以处理这些G时,调度器可能会创建新的M来增加并发处理能力。例如,在一个高并发的Web服务器应用中,短时间内接收了大量的HTTP请求,每个请求可能会启动一个G来处理,当G的数量超出了现有M的处理能力时,就会创建新的M。