面试题:后端
后端工程师岗位相关的接口设计、服务端基础、并发、存储和稳定性面试准备。
Go 的 goroutine、线程和进程分别承担什么并发边界?
goroutine 是由 Go runtime 调度的轻量执行单元,线程由操作系统执行,进程提供资源隔离;goroutine 成本低但仍受 CPU、内存和阻塞调用限制。
Go 调度器中的 G、M、P 分别是什么,GOMAXPROCS 影响什么?
G 表示 goroutine,M 表示操作系统线程,P 表示执行 Go 代码所需的调度资源;GOMAXPROCS 控制同时执行 Go 代码的 P 数量,通常与可用 CPU 能力相关。
Go channel 的无缓冲和有缓冲有什么区别,关闭规则怎样定义?
无缓冲 channel 让发送和接收同步交接,有缓冲 channel 允许有限数量的排队;关闭通常由发送方负责,接收方通过 range 或第二返回值感知结束。
Go select 如何处理多个 channel,为什么 default 可能造成忙等?
select 同时等待多个 channel 操作,准备好的分支中随机选择;default 让 select 立即返回,循环使用时可能持续占用 CPU。
Go context 如何传递取消、deadline 和请求范围值?
context 用于传递取消信号、截止时间和少量请求范围元数据;它应沿调用链显式传递,不能用作可变业务状态或长期存储。
sync.Mutex、RWMutex、Once 和 WaitGroup 分别适合什么协作?
Mutex 保护互斥临界区,RWMutex 适合读多写少,Once 保证初始化动作一次执行,WaitGroup 等待一组 goroutine 完成;它们不能互相替代。
Go map 为什么不能并发读写,应该怎样保护?
普通 map 不是并发安全结构,并发读写可能触发数据竞争或运行时错误;应使用 Mutex/RWMutex、sync.Map 或消息串行化。
Go slice 的长度、容量和底层数组有什么关系,append 为什么可能影响其他切片?
slice 是指向底层数组的描述结构,len 表示可见元素数,cap 表示从起始位置可扩展的容量;append 可能复用底层数组或重新分配。
Go interface 的动态类型和值为什么会产生 nil 陷阱?
interface 由动态类型和值共同构成,接口不为 nil 不代表其中的指针值不为 nil;错误返回和类型断言要明确处理。
Go error wrapping、errors.Is 和 errors.As 如何保留错误语义?
Go 错误应保留底层原因和可判断类型;用 %w 或 Wrap 形成链,errors.Is 判断特定原因,errors.As 提取特定类型。