面试题答案
一键面试性能瓶颈
- 竞争激烈时的等待开销:当多个 goroutine 频繁争夺互斥锁时,未获取到锁的 goroutine 会进入等待状态。这种等待会导致上下文切换,增加系统开销,降低程序的并发性能。
- 死锁风险:如果在代码中对互斥锁的使用逻辑不当,例如重复加锁或锁的嵌套使用顺序错误,可能会导致死锁。死锁发生时,相关 goroutine 会永久阻塞,使程序无法继续执行,严重影响性能。
- 锁粒度问题导致的低并发度:若互斥锁保护的临界区范围过大(锁粒度粗),会使得在同一时间内只有一个 goroutine 能访问该区域,即使临界区内不同部分的操作并不相互影响,这就限制了程序的并发执行能力,降低了整体性能。
- 饥饿现象:当高优先级的 goroutine 持续频繁获取锁时,低优先级的 goroutine 可能会长时间无法获取到锁,导致“饥饿”,影响其执行效率,进而影响整个程序的性能。
原因
- 操作系统调度机制:操作系统在处理 goroutine 上下文切换时,需要保存和恢复寄存器、栈等信息,这一过程涉及到内核态与用户态的切换,会消耗较多的 CPU 时间和内存资源,在竞争激烈时,频繁的上下文切换导致性能下降。
- 代码逻辑复杂性:程序逻辑复杂时,开发者难以清晰把控锁的使用顺序和范围,容易出现死锁情况。而且死锁一旦发生,排查和修复成本较高。
- 锁设计的局限性:粗粒度锁为了保证数据一致性,限制了多个 goroutine 对临界区不同部分的并发访问,而细粒度锁的设计和实现又需要开发者具备较高的并发编程技巧,否则可能引入其他问题。
- 公平性策略缺失:Go 语言的互斥锁默认不保证公平性,在高并发场景下,若没有合理的调度机制,容易出现低优先级 goroutine 饥饿的现象。