3.4. 性能优化技巧

3.4.1. 字符串优化

3.4.1.1. 使用 strings.Builder

// ❌ 每次拼接都分配新内存
func concat(strs []string) string {
    var result string
    for _, s := range strs {
        result += s
    }
    return result
}

// ✅ 使用 Builder
func concat(strs []string) string {
    var sb strings.Builder
    for _, s := range strs {
        sb.WriteString(s)
    }
    return sb.String()
}

// ✅ 预分配容量
func concat(strs []string) string {
    var sb strings.Builder
    size := 0
    for _, s := range strs {
        size += len(s)
    }
    sb.Grow(size)
    for _, s := range strs {
        sb.WriteString(s)
    }
    return sb.String()
}

3.4.1.2. 字符串与字节切片转换

// ❌ 产生拷贝
s := string(bytes)
b := []byte(str)

// ✅ 零拷贝转换(unsafe,谨慎使用)
import "unsafe"

func stringToBytes(s string) []byte {
    return unsafe.Slice(unsafe.StringData(s), len(s))
}

func bytesToString(b []byte) string {
    return unsafe.String(unsafe.SliceData(b), len(b))
}

3.4.2. 切片优化

3.4.2.1. 预分配容量

// ❌ 多次扩容
func createSlice(n int) []int {
    var s []int
    for i := 0; i < n; i++ {
        s = append(s, i)
    }
    return s
}

// ✅ 预分配
func createSlice(n int) []int {
    s := make([]int, 0, n)
    for i := 0; i < n; i++ {
        s = append(s, i)
    }
    return s
}

3.4.2.2. 避免切片引用导致的内存泄漏

// ❌ 小切片引用大数组,导致大数组无法被 GC
func getFirstElement(data []int) []int {
    return data[:1]  // 仍然引用原始大数组
}

// ✅ 复制数据
func getFirstElement(data []int) []int {
    result := make([]int, 1)
    copy(result, data[:1])
    return result
}

3.4.2.3. 复用切片

// ✅ 使用 slice[:0] 复用底层数组
func processInPlace(data []int) []int {
    result := data[:0]
    for _, v := range data {
        if v > 0 {
            result = append(result, v)
        }
    }
    return result
}

3.4.3. Map 优化

3.4.3.1. 预分配容量

// ❌ 动态扩容
m := make(map[string]int)

// ✅ 预分配
m := make(map[string]int, expectedSize)

3.4.3.2. 使用结构体 key 而非字符串

// ❌ 字符串 key 需要 hash 和比较
type cacheKey string
cache := make(map[cacheKey]Value)

// ✅ 固定大小的 key 更高效
type cacheKey struct {
    userID  int64
    itemID  int64
}
cache := make(map[cacheKey]Value)

3.4.4. 并发优化

3.4.4.1. 减少锁竞争

// ❌ 全局锁
type Counter struct {
    mu    sync.Mutex
    count int
}

// ✅ 分片锁减少竞争
type ShardedCounter struct {
    shards [256]struct {
        mu    sync.Mutex
        count int
    }
}

func (c *ShardedCounter) Inc(key string) {
    shard := &c.shards[hash(key)%256]
    shard.mu.Lock()
    shard.count++
    shard.mu.Unlock()
}

3.4.4.2. 使用 atomic 代替 Mutex

// ❌ 使用 Mutex
type Counter struct {
    mu    sync.Mutex
    count int64
}

func (c *Counter) Inc() {
    c.mu.Lock()
    c.count++
    c.mu.Unlock()
}

// ✅ 使用 atomic
type Counter struct {
    count atomic.Int64
}

func (c *Counter) Inc() {
    c.count.Add(1)
}

3.4.5. 内存分配优化

3.4.5.1. 使用 sync.Pool

var bufPool = sync.Pool{
    New: func() interface{} {
        return new(bytes.Buffer)
    },
}

func process(data []byte) []byte {
    buf := bufPool.Get().(*bytes.Buffer)
    defer func() {
        buf.Reset()
        bufPool.Put(buf)
    }()
    
    // 使用 buf 处理数据
    buf.Write(data)
    result := make([]byte, buf.Len())
    copy(result, buf.Bytes())
    return result
}

3.4.5.2. 避免不必要的指针

// ❌ 指针增加 GC 压力
type Item struct {
    Name  *string
    Value *int
}

// ✅ 值类型
type Item struct {
    Name  string
    Value int
}

3.4.6. I/O 优化

3.4.6.1. 使用 bufio

// ❌ 每次读取都是系统调用
func readLines(filename string) ([]string, error) {
    f, _ := os.Open(filename)
    defer f.Close()
    
    var lines []string
    buf := make([]byte, 1)
    for {
        _, err := f.Read(buf)
        // ...
    }
    return lines, nil
}

// ✅ 使用 bufio
func readLines(filename string) ([]string, error) {
    f, _ := os.Open(filename)
    defer f.Close()
    
    var lines []string
    scanner := bufio.NewScanner(f)
    for scanner.Scan() {
        lines = append(lines, scanner.Text())
    }
    return lines, scanner.Err()
}

3.4.6.2. 使用 io.Copy

// ❌ 手动复制
func copyFile(src, dst string) error {
    data, _ := os.ReadFile(src)  // 全部读入内存
    return os.WriteFile(dst, data, 0644)
}

// ✅ 流式复制
func copyFile(src, dst string) error {
    srcFile, _ := os.Open(src)
    defer srcFile.Close()
    
    dstFile, _ := os.Create(dst)
    defer dstFile.Close()
    
    _, err := io.Copy(dstFile, srcFile)
    return err
}

3.4.7. JSON 优化

3.4.7.1. 使用 json.Decoder/Encoder

// ❌ 中间缓冲区
data, _ := json.Marshal(obj)
w.Write(data)

// ✅ 直接写入
json.NewEncoder(w).Encode(obj)

3.4.7.2. 使用 jsoniter 或 sonic

import jsoniter "github.com/json-iterator/go"

var json = jsoniter.ConfigCompatibleWithStandardLibrary

func encode(v interface{}) ([]byte, error) {
    return json.Marshal(v)
}

3.4.8. 编译优化

3.4.8.1. 内联优化

// 小函数会被自动内联
//go:noinline  // 禁用内联
func add(a, b int) int {
    return a + b
}

3.4.8.2. 边界检查消除

// ❌ 每次访问都检查边界
func sum(s []int) int {
    total := 0
    for i := 0; i < len(s); i++ {
        total += s[i]
    }
    return total
}

// ✅ 使用 range 避免边界检查
func sum(s []int) int {
    total := 0
    for _, v := range s {
        total += v
    }
    return total
}

// ✅ 手动消除边界检查
func sum(s []int) int {
    total := 0
    _ = s[len(s)-1]  // 边界检查提前
    for i := 0; i < len(s); i++ {
        total += s[i]  // 不再检查
    }
    return total
}

3.4.9. 性能优化检查清单

检查清单

  1. [ ] 使用 -race 检查数据竞争

  2. [ ] 使用 pprof 找出热点

  3. [ ] 使用 -benchmem 检查内存分配

  4. [ ] 预分配切片和 map 容量

  5. [ ] 使用 strings.Builder 拼接字符串

  6. [ ] 使用 sync.Pool 复用对象

  7. [ ] 减少锁的粒度和持有时间

  8. [ ] 使用 bufio 进行 I/O

  9. [ ] 检查逃逸分析结果

  10. [ ] 使用基准测试验证优化效果

3.4.10. 参考资源