面试题答案
一键面试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上执行。
与操作系统线程的协作
- M与操作系统线程:每个M都绑定一个操作系统线程,M负责将分配到它上面的G调度到对应的操作系统线程上执行。
- P的作用:P提供了一个执行环境,M从P的本地G队列或者全局G队列中获取G来执行。P还负责管理一些与调度相关的状态,比如当前正在执行的G等。
- 调度流程:当一个G被创建时,它会被放入全局G队列或者某个P的本地G队列中。M在运行过程中,会首先尝试从其关联的P的本地G队列中获取G来执行,如果本地队列为空,则会尝试从全局G队列或者其他P的本地G队列中偷取G来执行。
创建新M与操作系统线程关联的情况
- G阻塞时:当一个M上运行的G执行系统调用(如I/O操作)而阻塞时,该M会被阻塞,但调度器为了不浪费CPU资源,会创建一个新的M,并将P绑定到这个新的M上,继续执行其他G。例如,当一个G执行
net.Dial
进行网络连接时,如果连接尚未建立,这个G会阻塞当前的M。此时,调度器会创建新的M,使得其他G可以继续在CPU上执行。 - G数量过多时:如果全局G队列和所有P的本地G队列中积累了大量的G,并且现有M的数量不足以处理这些G时,调度器可能会创建新的M来增加并发处理能力。例如,在一个高并发的Web服务器应用中,短时间内接收了大量的HTTP请求,每个请求可能会启动一个G来处理,当G的数量超出了现有M的处理能力时,就会创建新的M。