-
本文用 Go 接口返回 JSON 的现象入手,逐步验证 nil slice 和空 slice 在 len、cap、底层数组、json.Marshal 输出上的区别,并给出 API 响应保持 [] 的初始化方案。
-
本文回答 Go 里 sync.Once 为什么能保证函数只执行一次、多个协程同时调用时内部做了什么、以及在配置加载、单例初始化和懒加载里怎么安全复用。
-
本文回答 Go range 循环变量取地址为什么容易踩坑:旧语义下多个指针可能指向同一个循环变量,Go 1.22 后每轮变量语义改变,但如果目标是修改原切片元素,仍应使用索引取址。
-
用两个最小复现解释 Go slice 的 append 行为:当 cap 够用时会复用底层数组,原 slice 可能被间接改动;当 cap 不够时会分配新数组,后续修改互不影响。
-
用 Go 的接口值模型解释 typed nil 坑:接口变量由动态类型和动态值两部分组成,只有两者都为空才等于 nil;当 error 接口保存了 nil 指针但动态类型存在时,err != nil 会成立。
-
围绕 Go defer 在循环中的常见误用,解释为什么文件、连接、锁等资源会等到函数返回才释放,并给出函数拆分、显式关闭和错误处理的实战写法。
-
通过一个 Go map 并发读写 panic 案例,解释普通 map 为什么不是并发安全的,并对比 RWMutex、sync.Map、分片 map 和 channel 拥有者模式的适用场景。
-
atomic包基于CPU原子指令实现无锁并发操作。通过CAS操作实现变量的安全更新,避免使用锁带来的性能开销。相似问题及优化建议:CAS失败如何处理?atomic和Mutex区别?高并发如何选择同步方式?
-
Go语言的map在负载因子超过约6.5或溢出桶数量过多时触发扩容,并采用渐进式迁移而不是一次性重哈希。map底层使用哈希桶结构,每个桶可存储8个键值对。当元素增加导致负载过高时,会分配新的桶数组。旧桶中的数据不会一次性迁移,而是在后续写操作中逐步搬迁,减少性能抖动。同时删除元素过多时也可能触发等量扩容优化结构。相似问题及优化建议:map为什么不是线程安全的?因为底层未加锁。如何减少扩容带来的性能问题?可以提前指定容量。高并发场景下如何使用map?可使用sync.Map或加Mutex保护。
-
Go语言的select在多个case同时满足条件时采用伪随机算法选择执行分支,以避免饥饿问题。编译器会将case顺序打乱,通过runtime中的随机机制遍历case列表,保证公平性。这样可以防止固定顺序导致某些case长期得不到执行。相似问题及优化建议:select是否绝对公平?select如何避免阻塞?高并发场景如何设计select结构?避免case过多。
-
sync.Map适合读多写少的高并发场景。内部采用分段锁和只读副本结构优化读性能,不适合频繁写入场景。相似问题及优化建议:sync.Map和map+Mutex区别?什么时候不用sync.Map?如何优化高并发map?
-
sync.Pool用于缓存临时对象,减少频繁分配和回收带来的GC压力。对象放入Pool后可能在GC时被清空,因此适用于短生命周期对象缓存。适合高并发场景下减少内存分配次数,例如缓冲区复用。相似问题及优化建议:sync.Pool什么时候会被清空?sync.Pool适合长期对象缓存吗?如何正确使用对象池避免内存泄漏?
-
Go语言的context通过树状结构传播取消信号,实现协程间的统一控制。context内部维护done通道,当调用cancel函数时关闭该通道,所有监听该context的goroutine都会收到信号并退出。超时和截止时间本质也是通过定时器触发cancel实现。相似问题及优化建议:context为什么要传递下去?如何避免context滥用?高并发服务如何统一取消任务?
-
Mutex基于自旋锁与信号量机制实现。在竞争不激烈时使用自旋优化,竞争激烈时进入休眠等待队列,通过runtime调度器唤醒,减少CPU消耗。相似问题及优化建议:Mutex和RWMutex区别是什么?锁竞争严重怎么办?如何减少锁粒度提升性能?
-
可以通过减少内存分配、使用对象池、调整GOGC参数优化GC。pprof和trace工具可以分析内存分配热点,从而针对性优化。相似问题及优化建议:如何查看GC日志?GOGC参数如何设置?如何减少内存抖动?