← 方法反射 | 泛型 →

反射性能 - 性能分析与优化

反射虽然强大,但性能开销较大。理解反射的性能特征和优化技巧,以及在可能的情况下使用泛型替代,是编写高性能 Go 代码的关键。

性能开销

📊 反射性能对比

package main

import (
    "reflect"
    "testing"
)

type Person struct {
    Name string
    Age  int
}

// 直接访问
func DirectAccess(p Person) string {
    return p.Name
}

// 反射访问
func ReflectAccess(p Person) string {
    v := reflect.ValueOf(p)
    return v.FieldByName("Name").String()
}

// 基准测试结果 (Go 1.26, 参考值)
// BenchmarkDirectAccess-8    1000000000    0.3 ns/op
// BenchmarkReflectAccess-8     10000000    100 ns/op
// 反射慢约 300 倍

func BenchmarkDirectAccess(b *testing.B) {
    p := Person{Name: "Alice", Age: 30}
    for i := 0; i < b.N; i++ {
        _ = DirectAccess(p)
    }
}

func BenchmarkReflectAccess(b *testing.B) {
    p := Person{Name: "Alice", Age: 30}
    for i := 0; i < b.N; i++ {
        _ = ReflectAccess(p)
    }
}

⚠️ 反射性能要点

  • 慢 100-1000 倍: 反射比直接代码慢很多
  • 内存分配: 反射会创建临时对象
  • 无法内联: 反射调用无法被内联优化
  • 类型检查: 编译期无法检查类型错误

优化技巧

📝 反射优化方法

package main

import "reflect"

// 技巧 1: 缓存 Type 信息
var typeCache = make(map[reflect.Type][]int)

func getCachedFields(t reflect.Type) []int {
    if fields, ok := typeCache[t]; ok {
        return fields
    }
    // 计算并缓存
    return fields
}

// 技巧 2: 减少反射调用次数
func optimized(v reflect.Value) {
    // ❌ 不推荐:每次都调用 Field
    for i := 0; i < v.NumField(); i++ {
        _ = v.Field(i).Interface()
    }
    
    // ✅ 推荐:缓存 Field 值
    for i := 0; i < v.NumField(); i++ {
        field := v.Field(i)
        _ = field.Interface()
    }
}

// 技巧 3: 使用泛型替代 (Go 1.18+)
func GenericMap[T, U any](slice []T, fn func(T) U) []U {
    result := make([]U, len(slice))
    for i, v := range slice {
        result[i] = fn(v)
    }
    return result
}

替代方案

📝 泛型替代反射

// ❌ 反射版本
func ReflectFilter(slice interface{}, predicate interface{}) interface{} {
    // 复杂的反射逻辑
    // 性能差,类型不安全
}

// ✅ 泛型版本
func Filter[T any](slice []T, predicate func(T) bool) []T {
    result := []T{}
    for _, v := range slice {
        if predicate(v) {
            result = append(result, v)
        }
    }
    return result
}

// 泛型优势:
// 1. 类型安全
// 2. 性能更好
// 3. 代码更清晰

何时使用反射

✅ 反射适用场景

  • 框架开发: ORM、序列化库等
  • 通用工具: 无法预知类型的场景
  • 元编程: 代码生成、标签解析
  • 调试工具: 打印复杂结构

❌ 避免使用反射

  • 性能敏感: 高频调用路径
  • 简单场景: 可以用泛型或直接代码
  • 类型已知: 编译期已知类型

📖 延伸阅读