go面试知识点分类整理

📚 Go 面试知识点分类整理

基于 115 道面试题 | 11 大知识领域 | 代表性试题精选


目录

  1. [Go 语言基础](#Go 语言基础)
  2. 数据结构
  3. 并发编程
  4. 内存管理
  5. 垃圾回收
  6. 运行时调度
  7. 标准库
  8. 接口与反射
  9. 工程实践
  10. 性能优化
  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 能修改返回值吗?
点击查看答案

答案:

  1. 执行顺序:后进先出(LIFO)
  2. 参数立即求值
  3. 有名返回值可被 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 指针
}

遍历无序原因:

  1. 每次从随机桶、随机槽位开始
  2. 防止依赖实现细节
  3. 扩容后 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{}
}

使用场景:

  1. 超时控制:WithTimeout
  2. 取消信号:WithCancel
  3. 请求级数据: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")
}

关键点:

  1. 使用 Shutdown() 而非 Close()
  2. 设置合理超时时间
  3. 等待正在处理的请求完成
  4. 清理资源(数据库连接等)

📊 知识点掌握程度自测表

知识领域 了解 熟悉 精通 待加强
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 道代表性试题详解

相关推荐
@PHARAOH2 小时前
HOW - Go 开发入门(二)
开发语言·后端·golang
@PHARAOH2 小时前
HOW - Go 开发入门(四)- ORM 对象关系映射
开发语言·后端·golang
葡萄城技术团队3 小时前
Go 后端开发必知的 10 条最佳实践
go
ReSearch3 小时前
工业物联网的“瘦身”革命:Go 实现 20MB 级边缘存储,基于 LSM-Tree 的深度定制实践
数据库·go
白毛大侠3 小时前
理解 _ “github.com/go-sql-driver/mysql“:Go语言接口编程与init结合的经典案例
golang
程序员爱钓鱼4 小时前
Go图像处理基础: image包深度指南
后端·面试·go
keep intensify4 小时前
深度解析TCP三次握手四次挥手
网络·c++·后端·网络协议·tcp/ip·golang
xUxIAOrUIII5 小时前
【Go每日面试题】内存管理
java·开发语言·golang
江湖十年14 小时前
Go 并发控制:sync.Pool 详解
后端·面试·go