Go 并发编程面试题, Goroutine 什么时候会被挂起?
Go 并发编程面试题, Goroutine 什么时候会被挂起?
QA
Step 1
Q:: Goroutine 什么时候会被挂起?
A:: Goroutine 会在以下情况下被挂起:1) 通过 I/O 操作时,Goroutine 会等待系统调用完成;2)
在 channel 上进行阻塞操作时,比如 chan<-
或 <-chan
,没有可用的值或者无法接收;3)
当调用了 time.Sleep
等让出 CPU 的操作时;4)
当 Goroutine 主动调用 runtime.Gosched()
或 runtime.Goexit()
时;5)
在使用 Mutex 或 WaitGroup 等同步原语等待资源时。如果 Goroutine 遇到这些情况,它将被挂起,等待条件满足后再恢复执行。
Step 2
Q:: Goroutine 如何避免被不必要地挂起?
A:: 为了避免 Goroutine 被不必要地挂起,可以注意以下几点:1) 尽量减少 I/O 操作的阻塞时间,比如使用非阻塞 I/O;2) 在设计 channel 通信时,确保发送和接收双方都能够及时处理数据,避免死锁;3) 尽量减少不必要的同步操作,避免使用繁重的锁机制;4)
使用 context 包进行超时控制,避免 Goroutine 长时间等待资源。
Step 3
Q:: Goroutine 的调度策略是什么?
A:: Goroutine 的调度是由 Go 运行时的 M:
N 调度器完成的,其中 M 是操作系统线程数,N 是 Goroutine 数。调度器将多个 Goroutine 映射到少量的操作系统线程上,通过抢占和协作式调度机制实现高效的并发执行。Go 运行时会自动管理 Goroutine 的创建、销毁、挂起和恢复等操作,开发者无需手动干预。
Step 4
Q:: Goroutine 与操作系统线程的区别是什么?
A:: Goroutine 是 Go 语言级别的轻量级线程,消耗的资源远少于操作系统线程。Goroutine 的启动开销低,仅需数 KB 的栈空间,可以动态扩展,而操作系统线程通常需要数 MB 的栈空间,并且启动开销较大。Goroutine 依赖 Go 运行时进行调度,而操作系统线程则由操作系统内核调度。