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

133 lines
3.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 高级并发模式
来自 Effective Go 的高级并发模式详细参考。这些模式适用于特定场景 —— 在需要请求/响应多路复用或 CPU 密集型并行化时使用。
---
## Channel 的 Channel
> **来源**:Effective Go
Channel 是一等公民值,可以像其他值一样被分配和传递。一个强大的模式是在请求结构体中嵌入 **回复 channel**,让每个客户端提供自己的应答路径:
```go
type Request struct {
args []int
f func([]int) int
resultChan chan int
}
```
客户端发送一个包含函数、参数和接收结果 channel 的请求:
```go
request := &Request{[]int{3, 4, 5}, sum, make(chan int)}
clientRequests <- request
fmt.Printf("answer: %d\n", <-request.resultChan)
```
服务端处理器从队列中读取请求,并将结果发送回每个请求的回复 channel:
```go
func handle(queue chan *Request) {
for req := range queue {
req.resultChan <- req.f(req.args)
}
}
```
这个模式构成了限速、并行、非阻塞 RPC 系统的基础,无需任何互斥锁。
---
## CPU 密集型并行化
> **来源**:Effective Go(现代化版本)
当计算可以分解为独立的部分时,使用 `sync.WaitGroup` 等待完成,将其并行化到多个 CPU 核心上:
```go
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 将永远阻塞:
```go
// 不好:缺少 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 可能会耗尽内存或压垮下游资源。使用信号量来限制并发数:
```go
// 不好:一次性创建 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()
```