面试题答案
一键面试M(Machine)
- 作用:代表操作系统线程,是Go运行时与操作系统线程的抽象。每个M都绑定一个操作系统线程,负责执行Goroutine。它维护了一个本地运行队列,存放可运行的G。同时管理着与操作系统交互的一些状态,如栈的分配与回收等。
G(Goroutine)
- 作用:即Go协程,是Go语言中轻量级的用户态线程。它有自己独立的栈空间、程序计数器等,可并发执行。G代表了需要执行的任务,是调度的基本单位。它可以处于不同状态,如新建(new)、可运行(runnable)、运行中(running)、阻塞(blocked)等。
P(Processor)
- 作用:处理器,它包含了运行G所需要的资源,如G的本地运行队列、调度器的一些状态等。P的数量决定了同时能并发执行的G的数量上限(因为一个P同一时间只能执行一个G),它在M和G之间起到桥梁作用,协调两者的关系。
调度循环中的协作
- 初始化:程序启动时,会创建一定数量的M和P,每个P会初始化一个本地G队列。
- G的创建与分配:当创建新的Goroutine(G)时,它会被优先分配到当前P的本地队列中。如果本地队列已满,G会被放入全局队列。
- M获取P:M在启动时会尝试获取一个P。如果成功获取到P,M就可以从P的本地队列或全局队列中获取G来执行。如果P的本地队列和全局队列都为空,M会尝试从其他P的本地队列中偷取一半的G(work - stealing机制)。
- G的执行:M从P获取G后,将G的状态设为running并执行G的代码。在执行过程中,G可能会因为系统调用、I/O操作等原因进入阻塞状态,此时M会将G从运行状态改为阻塞状态,并将P释放,去寻找其他可运行的G或获取新的P。
- G执行完毕:当G执行完任务后,M会将其从P的队列中移除,然后M继续从P的队列中获取下一个G执行,若队列为空则重复work - stealing等操作获取G。如果M长时间没有获取到可运行的G,它可能会进入休眠状态等待被唤醒。