目录
Please enable Javascript to view the contents

Go — 速查手册

 ·  ☕ 3 分钟

1. GMP 调度模型

组件角色
G(Goroutine)执行体,每个 goroutine 对应一个 G
M(Machine)OS 线程,G 必须绑定到 M 才能执行
P(Processor)M 的上下文,持有本地 G 队列(默认 GOMAXPROCS 个)

work-stealing 机制:当本地 G 队列空时,M 先从全局队列取 G;全局队列也空时,从其他 P 的本地队列偷一半 G。

2. GC

Go 使用并发标记-清除(三色标记法)的 GC,关键阶段:

阶段说明
Mark Setup(STW)开启写屏障
Marking(并发)从根对象出发,三色标记可达对象
Mark Termination(STW)重新扫描,处理写屏障记录
Sweeping(并发)回收白色对象

写屏障保证并发标记期间不会漏标新分配或被修改指针的对象。

Go 1.19+ 进一步优化了软内存限制(GOMEMLIMIT),减少 STW 频率。

3. 栈与堆

分配时机编译期确定大小的局部变量new/make 或逃逸分析判定需堆分配的变量
生命周期函数返回即释放GC 回收
访问速度快(CPU cache 友好)慢(需指针解引用)
扩容Goroutine 栈动态扩展(初始 2KB)

逃逸分析:编译器判断变量是否在函数返回后仍被引用。引用了 → 分配在堆,未引用 → 在栈。

4. Slice 与 Array

ArraySlice
长度固定,类型的一部分([3]int动态
值/引用值类型(传参会复制)引用类型(底层数组共享)
使用频率极少

Slice 底层结构ptr(指针)+ len(长度)+ cap(容量)。对 Slice 切片产生的是新的 header,但底层数组共享。

扩容规则(Go 1.18+):

1
2
3
4
5
6
// 大致规则
if cap < 256 {
    newCap = 2 * oldCap
} else {
    newCap = oldCap + (oldCap + 3*256) / 4  // 渐进式增长
}

Go 切片 vs Python 切片

Go SlicePython Slice
底层共享数组创建新 list
修改成员影响原 Slice不影响原 list
负数索引不支持支持
[a🅱️c]c 是容量c 是步长

5. Channel 使用注意事项

操作nil channel已关闭 channel正常 channel
<-ch永久阻塞返回零值(可读尽)阻塞或读到值
ch <-永久阻塞panic阻塞或写入
关闭 close(ch)panicpanic成功

关键规则:

  • 不能向已关闭的 channel 写数据(panic)
  • 不能关闭 nil channel
  • 不能重复关闭 channel
  • 无缓冲 channel:读写同步,写等读、读等写
  • 有缓冲 channel:缓冲区未满时写不阻塞,缓冲区有数据时读不阻塞
  • 只有发送方应关闭 channel(接收方关闭可能 panic)

6. Mutex 注意事项

规则说明
Go 的 Mutex 不可重入同一 goroutine Lock 两次 → 死锁
谁 Lock 谁 Unlockgoroutine A Lock,goroutine B Unlock → 可编译通过但逻辑错误

RWMutex 额外规则:读锁之间不互斥,写锁与读写都互斥。不可升级(持有读锁时再 Lock 写锁 → 死锁)。

7. 值类型与引用类型

值类型引用类型
int, float, bool, stringslice, map, channel, pointer, interface
struct(字段全为值类型时)func
array

string 不可变(immutable),赋值和传参时复制的是 header(ptr+len),不是底层字节数组。

8. 线程安全的类型

Go 标准库中:

类型线程安全?说明
sync.Map读多写少场景优于 map + Mutex
chanchannel 操作本身是并发安全的
sync.Mutex / sync.RWMutex互斥锁本身就是线程安全机制
atomic.*原子操作
普通 map并发读写会 fatal error(非 panic,不可 recover)
slice并发 append 导致数据竞争
分享

Hex
作者
Hex
CloudNative Developer