Go 并发编程面试题, 什么是 Go 语言的 GPM 模型?
Go 并发编程面试题, 什么是 Go 语言的 GPM 模型?
QA
Step 1
Q:: 什么是 Go 语言的 GPM 模型?
A:: GPM 模型是 Go 语言实现并发的核心模型,其中 G 代表 Goroutine,P 代表 Processor(处理器),M 代表 Machine(机器)。在 Go 中,Goroutine 是轻量级的线程,P 负责管理和调度 Goroutine,而 M 代表真正的内核线程。GPM 模型通过将 Goroutine 和 P 绑定,并通过 M 将 P 映射到操作系统的线程,实现高效的并发执行。通过这种方式,Go 可以高效地管理数千甚至数百万个 Goroutine,避免线程上下文切换带来的开销。
Step 2
Q:: Go 语言的 Goroutine 与线程有什么区别?
A:: Goroutine 是 Go 语言中实现并发的基本单位,它比传统的线程更加轻量,通常只占用几 KB 的内存空间。与操作系统管理的线程不同,Goroutine 由 Go 运行时调度,避免了大量线程上下文切换的开销。多个 Goroutine 可以在一个线程内并发执行,Go 运行时会根据需要动态分配操作系统线程给 Goroutine 运行,因此在执行大规模并发任务时,Goroutine 更加高效。
Step 3
Q:: Go 语言的 P 是如何管理 Goroutine 的?
A:: 在 Go 语言的 GPM 模型中,P(Processor)是管理 Goroutine 的关键组件。每个 P 都维护着一个运行队列,保存着需要执行的 Goroutine。当 M(内核线程)被分配给一个 P 时,M 会从 P 的队列中获取 Goroutine 执行。如果一个 P 的队列中没有 Goroutine,Go 运行时会尝试从其他 P 的队列中窃取任务。这种设计允许 Go 运行时在多核 CPU 上高效地执行并发任务。
Step 4
Q:: Go 中如何实现 Goroutine 的调度?
A:: Go 运行时使用协作式调度来管理 Goroutine,这意味着 Goroutine 在特定的点(如 I/O 操作、系统调用或显式调用 runtime.
Gosched)时,主动放弃 CPU 控制权,使其他 Goroutine 有机会运行。Go 的调度器会根据 Goroutine 的状态(如阻塞、就绪)决定何时调度新的 Goroutine 到 M 上执行。这种调度机制使得 Goroutine 能够高效运行,并最大限度地减少阻塞。
Step 5
Q:: Go 的 runtime.
LockOSThread 函数有什么作用?
A:: runtime.LockOSThread 函数将当前的 Goroutine 锁定在当前的操作系统线程上。这在某些需要与操作系统线程直接交互的场景下非常有用,例如需要调用 C 库的 Go 程序。在调用 LockOSThread 后,该 Goroutine 以及之后在该 Goroutine 中创建的子 Goroutine 都会在同一线程上执行,直到显式调用 runtime.
UnlockOSThread 释放锁定。