Go 中的模式
Go 的运行时和标准库展示了干净、实用的模式实现。
| 模式 | Go 中的位置 | 作用 |
|---|---|---|
| 协作调度 | runtime/proc.go | 带协作抢占点的 goroutine 调度 |
| 位掩码 | os/types.go | FileMode — 通过 iota 类型常量实现的 Unix 权限标志 |
| 对象池 | sync/pool.go | sync.Pool — per-P 本地池,无锁快速路径,广泛用于 fmt、encoding/json |
| 工作窃取 | runtime/proc.go | stealWork — goroutine 调度器通过 runqsteal/runqgrab 从其他 P 的运行队列窃取 |
| 空闲链表 | runtime/mfixalloc.go | fixalloc — 固定大小空闲链表分配器,侵入式 mlink 节点 |
| LRU 缓存 | groupcache lru/lru.go | Cache 结构体,双向链表 + 哈希表,Brad Fitzpatrick 作品 |
| 一致性哈希 | groupcache consistenthash.go | 带虚拟节点的哈希环,用于分布式缓存 |
| 限流器 | x/time/rate | 扩展标准库中的令牌桶限流器 |
| 信号量 | x/sync/semaphore | 加权信号量——被 errgroup 内部使用以限制 goroutine 并发 |
| 享元 (Flyweight) | sync/pool.go | sync.Pool 作为享元——Get() 返回缓存实例而非分配新对象,Put() 归还以复用 |
| Arena 分配器 | arena/arena.go | 实验性 arena 分配器——New[T]() 分配,Free() 一次性释放绕过 GC |
模式如何协作:Goroutine 调度
当你执行 go func() 时,多个模式协同工作,在少量 OS 线程上运行数百万个 goroutine:
go func() { ... }▼5
信号量
当 goroutine 需要有界并发(如带限制的 errgroup)时,加权信号量控制同时运行的数量。
GMP 模型(Goroutine、M 线程、P 处理器)是粘合剂:每个 P 拥有本地运行队列、空闲链表分配器和 sync.Pool 分片。工作窃取只在 P 耗尽时才启动。这种设计意味着快速路径上大部分操作是无锁的,竞争只在窃取时发生——而窃取本身就是设计中的罕见情况。