Go 性能优化实战
Go 性能优化需要系统的方法论和合适的工具,理解原理才能有效调优。
一、性能分析工具
1.1 pprof
# CPU 分析
go test -cpuprofile=cpu.prof ./...
go tool pprof cpu.prof
# 内存分析
go test -memprofile=mem.prof ./...
go tool pprof mem.prof
# Web 界面
go tool pprof -http=:8080 cpu.prof
1.2 trace
# 生成 trace 文件
go test -trace=trace.out ./...
# 查看 trace
go tool trace trace.out
1.3 运行时统计
import "runtime"
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("Alloc = %v KB", m.Alloc/1024)
fmt.Printf("TotalAlloc = %v KB", m.TotalAlloc/1024)
fmt.Printf("Sys = %v KB", m.Sys/1024)
fmt.Printf("NumGC = %v", m.NumGC)
二、内存优化
2.1 减少分配
// ❌ 避免:频繁分配
for i := 0; i < 1000000; i++ {
s := make([]byte, 1024)
_ = s
}
// ✅ 推荐:复用内存
buf := make([]byte, 1024)
for i := 0; i < 1000000; i++ {
_ = buf[:1024]
}
2.2 sync.Pool
var bufferPool = sync.Pool{
New: func() any {
return make([]byte, 4096)
},
}
func getBuffer() []byte {
return bufferPool.Get().([]byte)
}
func putBuffer(buf []byte) {
bufferPool.Put(buf[:0])
}
2.3 预分配容量
// ❌ 避免:多次扩容
var slice []int
for i := 0; i < 1000000; i++ {
slice = append(slice, i)
}
// ✅ 推荐:预分配
slice := make([]int, 0, 1000000)
for i := 0; i < 1000000; i++ {
slice = append(slice, i)
}
2.4 字符串优化
// ❌ 避免:频繁拼接
s := ""
for i := 0; i < 10000; i++ {
s += strconv.Itoa(i)
}
// ✅ 推荐:strings.Builder
var builder strings.Builder
builder.Grow(10000 * 10) // 预分配
for i := 0; i < 10000; i++ {
builder.WriteString(strconv.Itoa(i))
}
s := builder.String()
三、并发优化
3.1 控制并发数
// ❌ 避免:无限制并发
for i := 0; i < 1000000; i++ {
go func() {
// ...
}()
}
// ✅ 推荐:限制并发数
sem := make(chan struct{}, 100)
for i := 0; i < 1000000; i++ {
sem <- struct{}{}
go func() {
defer func() { <-sem }()
// ...
}()
}
3.2 工作池模式
type WorkerPool struct {
jobs chan func()
workers int
}
func NewWorkerPool(workers int) *WorkerPool {
wp := &WorkerPool{
jobs: make(chan func(), 1000),
workers: workers,
}
for i := 0; i < workers; i++ {
go wp.worker()
}
return wp
}
func (wp *WorkerPool) worker() {
for job := range wp.jobs {
job()
}
}
func (wp *WorkerPool) Submit(job func()) {
wp.jobs <- job
}
3.3 避免 Goroutine 泄漏
// ❌ 避免:无退出条件
func worker(ch chan int) {
for v := range ch {
process(v)
}
}
// ✅ 推荐:使用 context
func worker(ctx context.Context, ch chan int) {
for {
select {
case <-ctx.Done():
return
case v := <-ch:
process(v)
}
}
}
四、I/O 优化
4.1 缓冲 I/O
// ❌ 避免:无缓冲
file, _ := os.Open("file.txt")
scanner := bufio.NewScanner(file)
for scanner.Scan() {
// ...
}
// ✅ 推荐:缓冲
file, _ := os.Open("file.txt")
reader := bufio.NewReaderSize(file, 32*1024)
for {
line, err := reader.ReadBytes('\n')
if err != nil {
break
}
// ...
}
4.2 批量操作
// ❌ 避免:逐条写入
for _, item := range items {
db.Exec("INSERT INTO table VALUES (?)", item)
}
// ✅ 推荐:批量写入
batch := make([]any, 0, 1000)
for i, item := range items {
batch = append(batch, item)
if (i+1) % 1000 == 0 {
db.Exec("INSERT INTO table VALUES (?)", batch)
batch = batch[:0]
}
}
4.3 连接池
// 数据库连接池
db, _ := sql.Open("mysql", dsn)
db.SetMaxOpenConns(100)
db.SetMaxIdleConns(50)
db.SetConnMaxLifetime(time.Hour)
// HTTP 连接池
transport := &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
}
client := &http.Client{Transport: transport}
五、CPU 优化
5.1 减少锁竞争
// ❌ 避免:全局锁
var mu sync.Mutex
func update() {
mu.Lock()
defer mu.Unlock()
// ...
}
// ✅ 推荐:分段锁
type ShardedMap struct {
shards [16]struct {
sync.RWMutex
data map[string]int
}
}
func (sm *ShardedMap) Get(key string) int {
shard := sm.getShard(key)
shard.RLock()
defer shard.RUnlock()
return shard.data[key]
}
5.2 使用原子操作
// ❌ 避免:锁保护计数器
var (
mu sync.Mutex
count int
)
func inc() {
mu.Lock()
count++
mu.Unlock()
}
// ✅ 推荐:原子操作
var count atomic.Int64
func inc() {
count.Add(1)
}
5.3 避免逃逸
// ❌ 避免:堆分配
func create() *LargeStruct {
return &LargeStruct{} // 逃逸到堆
}
// ✅ 推荐:栈分配
func process() {
var s LargeStruct // 栈上分配
use(s)
}
六、最佳实践
6.1 性能测试流程
1. 建立基准
2. 性能分析(pprof)
3. 识别瓶颈
4. 优化实现
5. 验证效果
6. 回归测试
6.2 优化原则
1. 先测量,后优化
2. 优先优化热点代码
3. 保持代码可读性
4. 避免过早优化
5. 验证优化效果
6.3 监控指标
// 关键指标
metrics := map[string]float64{
"latency_p99": latencyP99,
"throughput": throughput,
"error_rate": errorRate,
"memory_usage": memoryUsage,
"gc_pause": gcPause,
}
七、总结
Go 性能优化核心要点:
| 方面 | 优化方法 | 工具 |
|---|---|---|
| 内存 | 减少分配、复用、预分配 | pprof |
| 并发 | 控制并发数、工作池 | goroutine |
| I/O | 缓冲、批量、连接池 | bufio |
| CPU | 减少锁、原子操作 | atomic |
性能优化是系统工程,需要持续监控和迭代改进。