📚 Go 面试知识点分类整理
基于 115 道面试题 | 11 大知识领域 | 代表性试题精选
目录
1. Go 语言基础
📖 核心知识点
| 知识点 | 重要度 | 掌握要求 |
|---|---|---|
| 变量声明与作用域 | ⭐⭐ | 理解 var/:=区别 |
| 数据类型(基本/复合) | ⭐⭐ | 熟悉所有类型 |
| 函数参数传递 | ⭐⭐⭐ | 值传递本质 |
| defer/panic/recover | ⭐⭐⭐ | 执行顺序、恢复机制 |
| 初始化顺序 | ⭐⭐ | init() 执行流程 |
| 字符串处理 | ⭐⭐ | rune vs byte |
| 错误处理 | ⭐⭐ | error 接口、自定义错误 |
🎯 代表性面试题
Q1: Go 语言函数传参是值传递还是引用传递?
点击查看答案
答案:只有值传递
- 基本类型:值的副本
- 引用类型(slice/map/channel):拷贝引用(仍是指针副本)
- 指针类型:拷贝指针地址
go
// slice 作为参数
func modify(s []int) {
s[0] = 100 // ✅ 修改底层数组(共享)
s = append(s, 1) // ❌ 不影响原 slice(新副本)
}
// 指针作为参数
func modifyPtr(p *int) {
*p = 100 // ✅ 修改原值
}
Q2: defer 的执行顺序?defer 能修改返回值吗?
点击查看答案
答案:
- 执行顺序:后进先出(LIFO)
- 参数立即求值
- 有名返回值可被 defer 修改
go
// 无名返回值 - 不能修改
func f1() int {
a := 1
defer func() { a++ }()
return a // 返回 1
}
// 有名返回值 - 可以修改
func f2() (a int) {
a = 1
defer func() { a++ }()
return a // 返回 2
}
// 多个 defer
func f3() {
defer fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")
// 输出:3, 2, 1
}
Q3: init() 函数的执行顺序?
点击查看答案
答案:
程序启动 → import → const → var → init() → main()
依赖关系决定顺序:
1. 无依赖的包最先初始化
2. 按依赖树深度优先
3. 同一包内多个 init() 按源码顺序
go
// main.go
import (
_ "pkgA" // 先执行
_ "pkgB" // pkgB 依赖 pkgA,后执行
)
func init() { fmt.Println("main init") }
func main() { fmt.Println("main") }
// 输出:pkgA init → pkgB init → main init → main
2. 数据结构
📖 核心知识点
| 知识点 | 重要度 | 掌握要求 |
|---|---|---|
| 数组 vs 切片 | ⭐⭐⭐ | 底层结构、扩容 |
| 切片扩容机制 | ⭐⭐⭐ | 256 阈值、25% 增长 |
| Map 实现原理 | ⭐⭐⭐⭐ | hmap、bmap、哈希 |
| Map 扩容机制 | ⭐⭐⭐ | 渐进式、双倍/等量 |
| Channel 底层 | ⭐⭐⭐⭐ | hchan、环形缓冲 |
🎯 代表性面试题
Q4: 详细描述 slice 的扩容机制?
点击查看答案
答案:
Go 1.18+ 规则:
1. oldcap < 256:newcap = oldcap × 2
2. oldcap ≥ 256:
newcap = oldcap + (oldcap + 3×256) / 4
(约增长 25%)
go
s := make([]int, 0)
for i := 0; i < 10; i++ {
s = append(s, i)
fmt.Printf("len=%d, cap=%d\n", len(s), cap(s))
}
// 输出:
// len=1, cap=1
// len=2, cap=2
// len=3, cap=4 (翻倍)
// len=4, cap=4
// len=5, cap=8 (翻倍)
// len=6, cap=8
// len=7, cap=8
// len=8, cap=8
// len=9, cap=16 (翻倍)
// len=10, cap=16
内存布局:
slice 头 (24 字节)
┌─────────┬───────┬───────┐
│ array │ len │ cap │
└─────────┴───────┴───────┘
↓
底层数组 (连续内存)
┌───┬───┬───┬───┬───┬───┬───┬───┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │
└───┴───┴───┴───┴───┴───┴───┴───┘
Q5: Map 的底层实现原理?为什么遍历无序?
点击查看答案
答案:
底层结构:
go
type hmap struct {
count int // 元素个数
B uint8 // log2(桶数量)
buckets unsafe.Pointer // 桶数组
oldbuckets unsafe.Pointer // 旧桶(扩容时)
// ...
}
type bmap struct {
tophash [8]uint8 // 哈希高 8 位
// 8 个 key + 8 个 value
// overflow 指针
}
遍历无序原因:
- 每次从随机桶、随机槽位开始
- 防止依赖实现细节
- 扩容后 key 位置变化
go
m := map[int]int{1:1, 2:2, 3:3}
for i := 0; i < 3; i++ {
for k := range m {
fmt.Print(k, " ") // 每次顺序不同
}
fmt.Println()
}
Q6: Channel 的底层结构?发送/接收流程?
点击查看答案
答案:
hchan 结构:
go
type hchan struct {
qcount uint // 元素数量
dataqsiz uint // 缓冲区大小
buf unsafe.Pointer // 缓冲区指针
elemsize uint16 // 元素大小
closed uint32 // 是否关闭
sendx uint // 发送索引
recvx uint // 接收索引
recvq waitq // 接收等待队列
sendq waitq // 发送等待队列
lock mutex
}
发送流程:
1. 检查等待接收者 (recvq) → 直接传递(最高效)
2. 无等待者 → 写入缓冲区(如有空间)
3. 缓冲区满 → 阻塞等待(加入 sendq)
4. 已关闭 → panic
接收流程:
1. 检查等待发送者 (sendq) → 直接接收
2. 无等待者 → 从缓冲区读取
3. 缓冲区空 → 阻塞等待(加入 recvq)
4. 已关闭 + 空 → 返回零值 + false
3. 并发编程
📖 核心知识点
| 知识点 | 重要度 | 掌握要求 |
|---|---|---|
| Goroutine 原理 | ⭐⭐⭐⭐ | 用户态、栈伸缩 |
| Channel 通信 | ⭐⭐⭐⭐ | CSP 模型、使用场景 |
| select 多路复用 | ⭐⭐⭐⭐ | 随机选择、超时控制 |
| Mutex/RWMutex | ⭐⭐⭐⭐ | 正常/饥饿模式 |
| sync.Once | ⭐⭐⭐ | 双重检查锁 |
| sync.Map | ⭐⭐⭐ | 读写分离、适用场景 |
| WaitGroup | ⭐⭐⭐ | 原子计数器 |
| Context | ⭐⭐⭐⭐ | 超时、取消、传值 |
🎯 代表性面试题
Q7: Goroutine 和线程的区别?
点击查看答案
答案:
| 维度 | Goroutine | 线程 |
|---|---|---|
| 栈大小 | 2KB 起,动态伸缩 | 1MB 固定 |
| 调度 | 用户态(Go runtime) | 内核态(OS) |
| 切换开销 | 几十纳秒 | 几百纳秒 |
| 创建速度 | 微秒级 | 毫秒级 |
| 数量级 | 百万级 | 千级 |
| 通信 | channel | 共享内存+锁 |
go
// 创建 Goroutine(极轻量)
go func() { /* work */ }()
// 创建线程(Java 对比)
new Thread(() -> { /* work */ }).start()
Q8: Mutex 的两种模式及切换机制?
点击查看答案
答案:
正常模式(默认):
- 新 goroutine 可自旋竞争
- 吞吐量高,但可能饥饿
- 锁释放后:队头 + 新来者竞争
饥饿模式:
- 等待>1ms 触发切换
- 锁直接移交队头(公平)
- 新来者必须排队
状态位:
go
type Mutex struct {
state int32 // 位定义:
// bit0: mutexLocked
// bit1: mutexWoken
// bit2: mutexStarving
sema uint32 // 信号量
}
切换时机:
正常 → 饥饿:等待时间 > 1ms
饥饿 → 正常:等待队列为空 或 等待时间 < 1ms
Q9: Context 的使用场景和注意事项?
点击查看答案
答案:
四大方法:
go
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
使用场景:
- 超时控制:
WithTimeout - 取消信号:
WithCancel - 请求级数据:
WithValue
注意事项:
go
// ✅ 正确
func DoWork(ctx context.Context, arg int) {
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel() // 必须调用
}
// ❌ 错误
type Service struct {
ctx context.Context // 不要存储
}
// ✅ 正确:作为参数传递
func (s *Service) DoWork(ctx context.Context) error
4. 内存管理
📖 核心知识点
| 知识点 | 重要度 | 掌握要求 |
|---|---|---|
| 栈 vs 堆分配 | ⭐⭐⭐ | 逃逸分析 |
| 内存逃逸场景 | ⭐⭐⭐⭐ | 6 大常见场景 |
| 内存分配器 | ⭐⭐ | mcache/mcentral/mheap |
| 内存泄漏 | ⭐⭐⭐⭐ | 定位和修复 |
🎯 代表性面试题
Q10: 什么情况下会发生内存逃逸?如何分析?
点击查看答案
答案:
常见逃逸场景:
go
// 1. 返回局部变量指针
func newInt() *int {
x := 1
return &x // x 逃逸
}
// 2. interface{} 类型
func print(v interface{}) { // v 逃逸
fmt.Println(v)
}
// 3. 闭包引用外部变量
func counter() func() int {
count := 0 // count 逃逸
return func() int {
count++
return count
}
}
// 4. 切片/map 动态扩容
func grow() []int {
s := make([]int, 0)
for i := 0; i < 1000; i++ {
s = append(s, i) // 底层数组逃逸
}
return s
}
// 5. 大对象(超栈限制)
func big() {
var buf [1024 * 1024]byte // 1MB,可能逃逸
}
// 6. 全局变量引用
var global *int
func store() {
x := 1
global = &x // x 逃逸
}
分析方法:
bash
# 逃逸分析
go build -gcflags '-m -m -l' main.go
# 输出示例:
# ./main.go:5:6: &x escapes to heap
Q11: 如何定位和修复内存泄漏?
点击查看答案
答案:
定位工具:
bash
# 1. pprof heap 分析
go tool pprof http://localhost:6060/debug/pprof/heap
(pprof) top10
(pprof) web
# 2. goroutine 分析
go tool pprof http://localhost:6060/debug/pprof/goroutine
# 3. trace 可视化
go tool trace trace.out
# 4. runtime 监控
runtime.ReadMemStats()
runtime.NumGoroutine()
常见泄漏场景及修复:
1. Goroutine 泄漏
go
// ❌ 泄漏
func worker(ch <-chan int) {
for v := range ch { // ch 永不关闭
process(v)
}
}
// ✅ 修复
func worker(ctx context.Context, ch <-chan int) {
for {
select {
case v, ok := <-ch:
if !ok { return }
process(v)
case <-ctx.Done():
return
}
}
}
2. Timer 泄漏
go
// ❌ 泄漏
for {
select {
case <-time.After(time.Second): // 每次创建新 timer
doWork()
}
}
// ✅ 修复
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
doWork()
}
}
3. Slice 引用大数组
go
// ❌ 泄漏
func getFirst100(data []byte) []byte {
return data[:100] // 整个 data 无法回收
}
// ✅ 修复
func getFirst100(data []byte) []byte {
result := make([]byte, 100)
copy(result, data[:100])
return result
}
5. 垃圾回收
📖 核心知识点
| 知识点 | 重要度 | 掌握要求 |
|---|---|---|
| 三色标记法 | ⭐⭐⭐⭐ | 标记流程、不变性 |
| 写屏障机制 | ⭐⭐⭐⭐ | 混合写屏障 |
| GC 流程 | ⭐⭐⭐⭐ | 四阶段、STW 时间 |
| GC 调优 | ⭐⭐⭐ | GOGC、GOMEMLIMIT |
🎯 代表性面试题
Q12: 详细描述三色标记法?
点击查看答案
答案:
三色定义:
- 白色:未访问,待回收
- 灰色:已访问,引用未扫描
- 黑色:已访问且引用已扫描,存活
标记流程:
1. GC 开始,所有对象白色
2. GC Root 扫描,直接可达对象→灰色
3. 从灰色队列取对象,扫描引用:
- 引用对象白色→灰色
- 当前对象→黑色
4. 重复直到灰色队列为空
5. 白色对象回收
图解:
初始:Root → A(白) → B(白)
↓
C(白)
步骤 1:Root 扫描
Root → A(灰) → B(白)
↓
C(白)
步骤 2:A 扫描
Root → A(黑) → B(灰)
↓
C(灰)
步骤 3:B、C 扫描
Root → A(黑) → B(黑)
↓
C(黑)
最终:无白色对象,全部存活
Q13: GC 的四个阶段?STW 时间?
点击查看答案
答案:
| 阶段 | STW | 说明 | 时间 |
|---|---|---|---|
| SweepTermination | ✅ | 清扫终止,启动写屏障 | ~50μs |
| Mark | ❌ | 并发标记 | 1-10ms |
| MarkTermination | ✅ | 标记终止,停止写屏障 | ~50μs |
| GCoff | ❌ | 内存清扫 + 归还 | 并发 |
总 STW 时间:< 100μs(Go 1.12+)
GC 日志解读:
bash
GODEBUG=gctrace=1 ./app
gc 1 @0.000s 2%: 0.009+0.23+0.004 ms clock, 4->6->2 MB, 5 MB goal, 12 P
│ │ │ │ │ │ │ │ │ │ └─ P 数量
│ │ │ │ │ │ │ │ │ └─ 下次 GC 目标
│ │ │ │ │ │ │ │ └─ 存活对象
│ │ │ │ │ │ │ └─ GC 后堆大小
│ │ │ │ │ │ └─ GC 前堆大小
│ │ │ │ │ └─ 标记终止 STW
│ │ │ │ └────── 并发标记
│ │ │ └─────────── 标记开始 STW
│ │ └──────────────── CPU 使用率
│ └────────────────────────── 程序启动后时间
Q14: 如何调优 GC?
点击查看答案
答案:
调优参数:
bash
# GOGC:堆增长百分比触发 GC(默认 100%)
GOGC=200 ./app # 堆增长 200% 触发(减少频率)
GOGC=50 ./app # 堆增长 50% 触发(降低延迟)
# GOMEMLIMIT:内存上限(Go 1.19+)
GOMEMLIMIT=4GiB ./app
# GOMAXPROCS:并行度
GOMAXPROCS=8 ./app
优化手段:
go
// 1. 预分配容量
s := make([]int, 0, 1000) // 减少扩容
// 2. 对象池复用
var pool = sync.Pool{
New: func() interface{} {
return &Buffer{data: make([]byte, 1024)}
},
}
// 3. 减少逃逸
func create() Data { // 值返回,可能栈分配
return Data{}
}
// 4. strings.Builder
var b strings.Builder
b.Grow(4000) // 预分配
场景选择:
| 场景 | GOGC | 理由 |
|---|---|---|
| 延迟敏感(API) | 50-100 | 减少 STW 影响 |
| 吞吐优先(批处理) | 200-500 | 减少 GC 次数 |
| 内存受限 | 50 | 控制堆大小 |
| 内存充足 | 200+ | 减少 GC 开销 |
6. 运行时调度
📖 核心知识点
| 知识点 | 重要度 | 掌握要求 |
|---|---|---|
| GMP 模型 | ⭐⭐⭐⭐⭐ | 完整架构、调度流程 |
| 调度器 | ⭐⭐⭐⭐ | schedule() 逻辑 |
| 调度时机 | ⭐⭐⭐ | 阻塞、抢占 |
| 工作窃取 | ⭐⭐⭐ | 平衡负载 |
| g0 协程 | ⭐⭐⭐ | 调度栈、作用 |
🎯 代表性面试题
Q15: 详细描述 GMP 模型?
点击查看答案
答案:
架构图:
┌─────────────────────────────────────────┐
│ Go Runtime │
│ │
│ G1 G2 G3 G4 G5 G6 G7 │
│ │ │ │ │ │ │ │ │
│ └───┴───┘ └───┘ └───┘ │
│ │ │ │ │
│ ┌──┴───┐ ┌──┴───┐ ┌──┴───┐ │
│ │ P0 │ │ P1 │ │ P2 │ │ ← Local Queue
│ │ [..] │ │ [..] │ │ [..] │ │
│ └──┬───┘ └──┬───┘ └──┬───┘ │
│ │ │ │ │
│ ┌──┴───┐ ┌──┴───┐ ┌──┴───┐ │
│ │ M0 │ │ M1 │ │ M2 │ │ ← OS Thread
│ └──────┘ └──────┘ └──────┘ │
│ │
│ ┌────────────────────┐ │
│ │ Global Queue │ │
│ │ [G8][G9][G10] │ │
│ └────────────────────┘ │
└─────────────────────────────────────────┘
核心组件:
- G (Goroutine):协程,2KB 栈,包含执行上下文
- M (Machine):系统线程,真正执行 G
- P (Processor):逻辑处理器,维护本地队列(256)
调度流程:
1. G 创建 → 放入 P 的本地队列
2. M 绑定 P,从本地队列获取 G 执行
3. G 阻塞/完成 → M 寻找其他 G
4. 本地队列空 → 全局队列 → 工作窃取
Q16: 发生调度的时机有哪些?
点击查看答案
答案:
主动让出:
go
// 1. Channel 阻塞
<-ch // 阻塞接收
ch <- 1 // 阻塞发送
// 2. 锁等待
mu.Lock() // 阻塞等待锁
// 3. 时间等待
time.Sleep(time.Second)
<-time.After(time.Second)
// 4. 系统调用
os.Read()
os.Write()
被动抢占(Go 1.14+):
go
// sysmon 检测到 G 运行>10ms 发送 SIGURG 信号
func longLoop() {
for i := 0; i < 1000000000; i++ {
// Go 1.14+ 会被异步抢占
}
}
调度流程:
G 运行 → 发生调度事件 → 保存上下文 → G 状态变更
→ M 切换 g0 → schedule() 找新 G → 恢复上下文 → 继续运行
7. 标准库
📖 核心知识点
| 知识点 | 重要度 | 掌握要求 |
|---|---|---|
| net/http | ⭐⭐⭐ | Server、Handler、中间件 |
| encoding/json | ⭐⭐⭐ | 序列化、tag、自定义 |
| time | ⭐⭐ | Timer、Ticker、Sleep |
| io | ⭐⭐ | Reader、Writer 接口 |
| sync | ⭐⭐⭐⭐ | 所有并发原语 |
🎯 代表性面试题
Q17: HTTP 中间件如何实现?
点击查看答案
答案:
中间件模式:
go
// 1. 基础中间件
func LoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %v", r.Method, r.URL, time.Since(start))
})
}
// 2. 链式调用
func ChainMiddleware(handler http.Handler, middlewares ...func(http.Handler) http.Handler) http.Handler {
for i := len(middlewares) - 1; i >= 0; i-- {
handler = middlewares[i](handler)
}
return handler
}
// 3. 使用示例
mux := http.NewServeMux()
mux.HandleFunc("/api", handler)
handler := ChainMiddleware(mux,
LoggingMiddleware,
RecoveryMiddleware,
AuthMiddleware,
)
http.ListenAndServe(":8080", handler)
8. 接口与反射
📖 核心知识点
| 知识点 | 重要度 | 掌握要求 |
|---|---|---|
| interface 底层 | ⭐⭐⭐⭐ | eface、iface、itab |
| 类型断言 | ⭐⭐⭐ | 安全方式、type switch |
| 反射原理 | ⭐⭐⭐ | TypeOf、ValueOf |
| 反射应用 | ⭐⭐ | JSON、ORM、框架 |
🎯 代表性面试题
Q18: interface 的底层实现?
点击查看答案
答案:
两种结构:
go
// eface(空接口)
type eface struct {
_type *_type // 类型信息
data unsafe.Pointer // 数据指针
}
// 对应:interface{}
// iface(带方法接口)
type iface struct {
tab *itab // 类型 + 方法表
data unsafe.Pointer // 数据指针
}
type itab struct {
inter *interfacetype // 接口类型
_type *_type // 具体类型
hash uint32
fun [1]uintptr // 方法表(函数指针数组)
}
内存布局:
eface (16 字节)
┌─────────────┬─────────────┐
│ _type │ data │
└─────────────┴─────────────┘
iface (16 字节)
┌─────────────┬─────────────┐
│ tab │ data │
└─────────────┴─────────────┘
↓
itab (动态大小)
┌─────────────────────────┐
│ inter (接口类型) │
│ _type (具体类型) │
│ fun[0] (方法 1 指针) │
│ fun[1] (方法 2 指针) │
└─────────────────────────┘
经典陷阱:
go
type Dog struct{}
func (d *Dog) Speak() string { return "woof" }
var s interface{} = (*Dog)(nil)
fmt.Println(s == nil) // false!
// 原因:s 的_type=*Dog,data=nil
// interface 本身不是 nil(_type 非 nil)
9. 工程实践
📖 核心知识点
| 知识点 | 重要度 | 掌握要求 |
|---|---|---|
| 错误处理 | ⭐⭐⭐ | error 接口、errors.Wrap |
| 日志管理 | ⭐⭐ | 结构化日志、级别 |
| 配置管理 | ⭐⭐ | 环境变量、配置文件 |
| 测试 | ⭐⭐⭐ | 单元测试、基准测试 |
| 代码规范 | ⭐⭐ | gofmt、golint |
🎯 代表性面试题
Q19: Go 的错误处理最佳实践?
点击查看答案
答案:
1. 基础错误处理
go
// ✅ 立即检查
result, err := doWork()
if err != nil {
return fmt.Errorf("do work: %w", err)
}
// ❌ 忽略错误
result, _ := doWork() // 除非确定不会错
2. 错误包装
go
// Go 1.13+
if err != nil {
return fmt.Errorf("open file: %w", err)
}
// 判断错误
if errors.Is(err, os.ErrNotExist) {
// 处理特定错误
}
// 解包错误
var target *MyError
if errors.As(err, &target) {
// 提取具体错误类型
}
3. 自定义错误
go
type MyError struct {
Code int
Message string
}
func (e *MyError) Error() string {
return fmt.Sprintf("[%d] %s", e.Code, e.Message)
}
10. 性能优化
📖 核心知识点
| 知识点 | 重要度 | 掌握要求 |
|---|---|---|
| 性能分析 | ⭐⭐⭐⭐ | pprof、trace |
| 内存优化 | ⭐⭐⭐ | 减少分配、对象池 |
| 并发优化 | ⭐⭐⭐ | 减少锁竞争、worker pool |
| 基准测试 | ⭐⭐⭐ | go test -bench |
🎯 代表性面试题
Q20: 如何进行性能分析和优化?
点击查看答案
答案:
性能分析工具:
bash
# 1. CPU profile
go test -cpuprofile=cpu.prof
go tool pprof cpu.prof
# 2. Heap profile
go test -memprofile=mem.prof
go tool pprof mem.prof
# 3. Block profile
go test -blockprofile=block.prof
# 4. Trace
go test -trace=trace.out
go tool trace trace.out
优化手段:
1. 减少内存分配
go
// ❌ 频繁分配
for i := 0; i < 1000; i++ {
s := make([]byte, 1024)
}
// ✅ 预分配 + 复用
buf := make([]byte, 1024)
for i := 0; i < 1000; i++ {
// 复用 buf
}
2. 减少锁竞争
go
// ❌ 全局锁
var mu sync.Mutex
mu.Lock()
// ✅ 分片锁
var shards [16]sync.Mutex
shards[i%16].Lock()
3. 使用 sync.Pool
go
var pool = sync.Pool{
New: func() interface{} {
return &bytes.Buffer{}
},
}
buf := pool.Get().(*bytes.Buffer)
defer pool.Put(buf)
11. 架构设计
📖 核心知识点
| 知识点 | 重要度 | 掌握要求 |
|---|---|---|
| 微服务 | ⭐⭐ | 服务拆分、通信 |
| 并发模式 | ⭐⭐⭐ | worker pool、fan-in/out |
| 优雅关闭 | ⭐⭐⭐ | signal、context |
| 可观测性 | ⭐⭐ | 日志、指标、链路追踪 |
🎯 代表性面试题
Q21: 如何实现服务的优雅关闭?
点击查看答案
答案:
完整示例:
go
func main() {
// 1. 创建 HTTP server
server := &http.Server{
Addr: ":8080",
Handler: mux,
}
// 2. 启动 server
go func() {
if err := server.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
}()
// 3. 监听退出信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
// 4. 优雅关闭
ctx, cancel := context.WithTimeout(
context.Background(),
5*time.Second,
)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Fatal(err)
}
log.Println("Server stopped")
}
关键点:
- 使用
Shutdown()而非Close() - 设置合理超时时间
- 等待正在处理的请求完成
- 清理资源(数据库连接等)
📊 知识点掌握程度自测表
| 知识领域 | 了解 | 熟悉 | 精通 | 待加强 |
|---|---|---|---|---|
| Go 基础 | □ | □ | □ | □ |
| 数据结构 | □ | □ | □ | □ |
| 并发编程 | □ | □ | □ | □ |
| 内存管理 | □ | □ | □ | □ |
| 垃圾回收 | □ | □ | □ | □ |
| 运行时调度 | □ | □ | □ | □ |
| 标准库 | □ | □ | □ | □ |
| 接口与反射 | □ | □ | □ | □ |
| 工程实践 | □ | □ | □ | □ |
| 性能优化 | □ | □ | □ | □ |
| 架构设计 | □ | □ | □ | □ |
🎯 复习建议
第 1 周:基础巩固
- Go 基础语法(Q1-Q3)
- 数据结构(Q4-Q6)
- 每日 10 道 Anki 卡片
第 2 周:并发突破
- Goroutine、Channel(Q7-Q9)
- Sync 包原语
- 手写 worker pool
第 3 周:底层原理
- GMP 模型(Q15-Q16)
- GC 机制(Q12-Q14)
- 内存管理(Q10-Q11)
第 4 周:综合实战
- 完成 8 道模拟题
- 模拟面试练习
- 查漏补缺
文档版本:v1.0 | 最后更新:2026-03-18
基于 115 道面试题整理 | 21 道代表性试题详解