Files
OpenFlare/.agents/skills/go-concurrency/references/ADVANCED-PATTERNS.md
T
2026-08-04 11:40:32 +08:00

3.1 KiB
Raw Blame History

高级并发模式

来自 Effective Go 的高级并发模式详细参考。这些模式适用于特定场景 —— 在需要请求/响应多路复用或 CPU 密集型并行化时使用。


Channel 的 Channel

来源:Effective Go

Channel 是一等公民值,可以像其他值一样被分配和传递。一个强大的模式是在请求结构体中嵌入 回复 channel,让每个客户端提供自己的应答路径:

type Request struct {
    args       []int
    f          func([]int) int
    resultChan chan int
}

客户端发送一个包含函数、参数和接收结果 channel 的请求:

request := &Request{[]int{3, 4, 5}, sum, make(chan int)}
clientRequests <- request
fmt.Printf("answer: %d\n", <-request.resultChan)

服务端处理器从队列中读取请求,并将结果发送回每个请求的回复 channel:

func handle(queue chan *Request) {
    for req := range queue {
        req.resultChan <- req.f(req.args)
    }
}

这个模式构成了限速、并行、非阻塞 RPC 系统的基础,无需任何互斥锁。


CPU 密集型并行化

来源:Effective Go(现代化版本)

当计算可以分解为独立的部分时,使用 sync.WaitGroup 等待完成,将其并行化到多个 CPU 核心上:

type Vector []float64

func (v Vector) DoSome(i, n int, u Vector) {
    for ; i < n; i++ {
        v[i] += u.Op(v[i])
    }
}

func (v Vector) DoAll(u Vector) {
    numCPU := runtime.NumCPU()
    var wg sync.WaitGroup
    wg.Add(numCPU)
    for i := 0; i < numCPU; i++ {
        go func(i int) {
            defer wg.Done()
            v.DoSome(i*len(v)/numCPU, (i+1)*len(v)/numCPU, u)
        }(i)
    }
    wg.Wait()
}

使用 runtime.NumCPU() 获取硬件核心数,或使用 runtime.GOMAXPROCS(0) 以遵循用户的资源配置。

重要:不要混淆并发(将程序组织为独立执行的组件)和并行(在多个 CPU 上同时执行计算)。Go 是一门并发语言;并非所有并行化问题都适合它的模型。


常见错误

忘记通知完成

如果 goroutine 从未调用 wg.Done()(或从未在 done channel 上发送),等待的 goroutine 将永远阻塞:

// 不好:缺少 wg.Done —— 死锁
var wg sync.WaitGroup
wg.Add(1)
go func() {
    doWork()
}()
wg.Wait()

// 好:始终 defer wg.Done
var wg sync.WaitGroup
wg.Add(1)
go func() {
    defer wg.Done()
    doWork()
}()
wg.Wait()

无限制的 goroutine 创建

为每个工作项无限制地启动 goroutine 可能会耗尽内存或压垮下游资源。使用信号量来限制并发数:

// 不好:一次性创建 len(items) 个 goroutine
var wg sync.WaitGroup
for _, item := range items {
    wg.Add(1)
    go func(it Item) {
        defer wg.Done()
        process(it)
    }(item)
}
wg.Wait()

// 好:信号量将并发限制为 maxWorkers
var wg sync.WaitGroup
sem := make(chan struct{}, maxWorkers)
for _, item := range items {
    wg.Add(1)
    sem <- struct{}{}
    go func(it Item) {
        defer wg.Done()
        defer func() { <-sem }()
        process(it)
    }(item)
}
wg.Wait()