面试题答案
一键面试M:N模型简述
在Go调度器的M:N模型中,M代表操作系统线程(Machine threads),N代表协程(Goroutines)。它将多个协程映射到多个操作系统线程上,实现高效的并发执行。
M和N的含义
- M(操作系统线程):是操作系统层面的线程,由操作系统内核进行调度和管理。它们负责实际执行CPU指令,每个M有自己的栈空间等资源。
- N(协程):是Go语言层面的轻量级线程,由Go运行时(runtime)调度器管理。协程的创建、销毁和调度开销非常小,多个协程可以复用一个操作系统线程。
优势
- 高效利用资源:由于协程非常轻量级,创建和销毁开销小,可以在有限的操作系统线程上运行大量协程,减少了线程切换的开销和内存占用,提高了系统资源的利用率。
- 并发性能优越:通过M:N模型,Go调度器可以灵活地将协程调度到不同的操作系统线程上执行,充分利用多核CPU的优势,实现高效的并发编程。
- 简化编程模型:开发者无需关心底层线程的创建、销毁和调度细节,只需要专注于业务逻辑的实现,通过Go语言的
go
关键字轻松创建协程,使得并发编程更加简单和直观。
实现原理
- Goroutine创建:当使用
go
关键字创建一个协程时,Go运行时会在堆上为其分配一个g
结构体,该结构体包含了协程的栈空间、程序计数器、寄存器等信息。 - 调度器结构:Go调度器主要由
M
(Machine)、P
(Processor)和G
(Goroutine)组成。P
是逻辑处理器,它维护着一个本地的协程队列,同时也关联一个操作系统线程M
。每个P
负责管理一部分协程,并且在某个时刻只能绑定到一个M
上。 - 调度过程:
- 初始状态:协程创建后,会被放入某个
P
的本地队列或者全局队列中。 - 执行过程:
M
从绑定的P
的本地队列中获取协程来执行。如果本地队列为空,M
会尝试从全局队列或者其他P
的本地队列中偷取协程(work - stealing机制)。 - 阻塞处理:当一个协程执行系统调用等阻塞操作时,其所在的
M
会阻塞。此时,Go调度器会将该M
上的其他协程迁移到其他P
上继续执行,同时创建一个新的M
来处理阻塞完成后的协程,保证系统的并发性能。 - 调度时机:协程在执行过程中,会在一些特定的点(如函数调用、系统调用、channel操作等)主动让出执行权,调度器会根据调度策略选择下一个要执行的协程,从而实现多个协程在多个操作系统线程上的高效调度。
- 初始状态:协程创建后,会被放入某个