跳到主要内容

并发编程知识体系概览

什么是 Go 并发?

Go 的并发编程基于 CSP(Communicating Sequential Processes) 模型——通过通信来共享内存,而不是通过共享内存来通信。这是 Go 与 Java、C++ 等语言并发模型最根本的区别。

"Do not communicate by sharing memory; instead, share memory by communicating." — Go Proverb

Go 提供了两个语言级并发原语:

  • Goroutine:轻量级协程,比 OS 线程轻 1000 倍(初始栈 2-8KB)
  • Channel:类型安全的消息传递管道

为什么 Go 的并发这么强?

维度Go GoroutineJava ThreadLinux Thread
创建开销~2KB 栈~512KB-1MB 栈~8MB 栈
切换开销~几十 ns(用户态)~几 μs(内核态)~几 μs(内核态)
调度方式Go runtime 调度(M:NOS 内核调度(1:1)OS 内核调度
可同时创建数量百万级千到万级千到万级
通信方式Channel(首选) + syncsynchronized + Lockmutex + semaphore

核心知识点

GMP 调度模型

Go 的调度器使用 GMP 模型实现 goroutine 到 OS 线程的映射:

  • G(Goroutine):用户态协程,携带函数调用栈
  • M(Machine):OS 线程,真正执行代码的载体
  • P(Processor):逻辑处理器,维护本地 G 队列,数量默认等于 CPU 核数(GOMAXPROCS

调度核心机制:

  1. 本地队列:每个 P 有本地运行队列(最多 256 个 G),减少锁竞争
  2. 全局队列:本地队列满时溢出到全局队列
  3. 工作窃取(Work Stealing):P 的本地队列空时,从其他 P 或全局队列窃取 G
  4. 抢占式调度:Go 1.14 引入基于信号的异步抢占,避免单个 G 长期占用

Channel——goroutine 间的管道

Channel 是 Go 并发的核心通信机制,类型安全、线程安全:

// 无缓冲 channel:发送和接收同步(握手)
ch := make(chan int)

// 有缓冲 channel:缓冲区满时发送阻塞,空时接收阻塞
ch := make(chan int, 10)

// 单向 channel(用于函数签名约束)
func producer(out chan<- int) { out <- 42 }
func consumer(in <-chan int) { val := <-in }

Channel 的关闭语义是重要面试题——详见 Channel 详解

sync 包——互斥与同步

虽然 Go 推崇 Channel,但 sync 包在保护共享状态时更高效:

工具用途
sync.Mutex互斥锁
sync.RWMutex读写锁(多读一写)
sync.WaitGroup等待一组 goroutine 完成
sync.Once只执行一次(单例)
sync.Map并发安全 map
sync.Cond条件变量
sync.Pool对象池(减少 GC 压力)

Context——传递取消信号和截止时间

context.Context 是 Go 并发编程的"黏合剂",用于:

  • 取消信号传播:上游取消时,下游所有 goroutine 收到通知
  • 截止时间:设置超时,避免 goroutine 无限等待
  • 传递请求范围的值:如 RequestID、UserID

详见 Context 详解

并发模式

Go 有一套成熟的并发模式:

模式说明适用场景
Fan-out一个输入分发到多个 worker并行处理
Fan-in多个输入合并到一个输出结果聚合
Pipeline多阶段串联,每阶段是独立 goroutine数据处理流水线
Worker Pool固定数量的 worker 消费任务队列限制并发度
Semaphore用带缓冲的 channel 限制并发资源访问限流

详见并发模式


Channel vs Mutex 选择依据

场景ChannelMutex
传递数据的所有权
协调多个 goroutine
保护共享状态
简单的计数器/标志✅(或 atomic)
生产者-消费者模型
经验法则
  • 如果需要传递数据通知事件→ 用 Channel
  • 如果需要保护共享状态(缓存、计数器)→ 用 Mutex
  • 如果是简单的原子操作→ 用 sync/atomic

学习建议

推荐学习路径
  1. Goroutine 与调度器 → 理解 GMP 模型、goroutine 生命周期
  2. Channel → 有缓冲/无缓冲、关闭语义、select
  3. sync 包 → Mutex、WaitGroup、Once、Map
  4. Context → 取消传播、超时控制
  5. 并发模式 → Pipeline、Worker Pool、Fan-in/Fan-out
  6. 数据竞争 → race detector、常见竞态

相关链接