package reflux // 新实现(rfx: 类型布局缓存 + unsafe 指针运算)与老实现(refx: 逐次 reflect)的对比。 // // 两者在同一个包、同一次进程里跑, 用完全相同的数据结构和路径, 结果可直接比较。 // newLegacy 构造的就是合并前的实现, 见 rfx_contract_test.go。 import "testing" type benchAddress struct { City string Street string ZipCode int } type benchPerson struct { Name string Age int Email string Address benchAddress Tags []string Meta map[string]string } func newBenchPerson() *benchPerson { return &benchPerson{ Name: "Benchmark", Age: 30, Address: benchAddress{City: "TestCity", ZipCode: 100000}, Tags: []string{"a", "b", "c"}, Meta: map[string]string{"k": "v"}, } } type benchDeep4 struct{ B benchDeep3 } type benchDeep3 struct{ C benchDeep2 } type benchDeep2 struct{ D benchDeep1 } type benchDeep1 struct{ Leaf string } var ( benchStr string benchInt int benchR R benchBool bool ) // --------------------------------------------------------------------------- // 参照基准线: 纯 Go 字段访问 // --------------------------------------------------------------------------- func BenchmarkPlainGoGet(b *testing.B) { p := newBenchPerson() b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = p.Address.City } } // --------------------------------------------------------------------------- // Get: 嵌套字段 // --------------------------------------------------------------------------- func BenchmarkGetLegacy(b *testing.B) { r := newLegacy(newBenchPerson()) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = r.Get("Address", "City").String() } } func BenchmarkGetNew(b *testing.B) { r := New(newBenchPerson()) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = r.Get("Address", "City").String() } } func BenchmarkGetGeneric(b *testing.B) { r := New(newBenchPerson()) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = Get[string](r, "Address", "City") } } // 点号路径 func BenchmarkGetDottedLegacy(b *testing.B) { r := newLegacy(newBenchPerson()) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = r.Get("Address.City").String() } } func BenchmarkGetDottedNew(b *testing.B) { r := New(newBenchPerson()) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = r.Get("Address.City").String() } } // 4 层深路径 func BenchmarkGetDeepLegacy(b *testing.B) { r := newLegacy(&benchDeep4{B: benchDeep3{C: benchDeep2{D: benchDeep1{Leaf: "deep"}}}}) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = r.Get("B", "C", "D", "Leaf").String() } } func BenchmarkGetDeepNew(b *testing.B) { r := New(&benchDeep4{B: benchDeep3{C: benchDeep2{D: benchDeep1{Leaf: "deep"}}}}) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = r.Get("B", "C", "D", "Leaf").String() } } func BenchmarkGetDeepGeneric(b *testing.B) { r := New(&benchDeep4{B: benchDeep3{C: benchDeep2{D: benchDeep1{Leaf: "deep"}}}}) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = Get[string](r, "B", "C", "D", "Leaf") } } // slice 下标 func BenchmarkGetSliceIndexLegacy(b *testing.B) { r := newLegacy(newBenchPerson()) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = r.Get("Tags", "1").String() } } func BenchmarkGetSliceIndexNew(b *testing.B) { r := New(newBenchPerson()) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = r.Get("Tags", "1").String() } } // map 键 func BenchmarkGetMapKeyLegacy(b *testing.B) { r := newLegacy(newBenchPerson()) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = r.Get("Meta", "k").String() } } func BenchmarkGetMapKeyNew(b *testing.B) { r := New(newBenchPerson()) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = r.Get("Meta", "k").String() } } // --------------------------------------------------------------------------- // Set // --------------------------------------------------------------------------- func BenchmarkSetLegacy(b *testing.B) { r := newLegacy(&benchPerson{}) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { r.Set("Name", "TestName") } } func BenchmarkSetNew(b *testing.B) { r := New(&benchPerson{}) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { r.Set("Name", "TestName") } } func BenchmarkSetNestedLegacy(b *testing.B) { r := newLegacy(&benchPerson{}) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { r.Set("Address.City", "TestCity") } } func BenchmarkSetNestedNew(b *testing.B) { r := New(&benchPerson{}) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { r.Set("Address.City", "TestCity") } } // --------------------------------------------------------------------------- // 访问器: 纯类型转换开销(循环外先取到目标值) // --------------------------------------------------------------------------- func BenchmarkAccessorStringLegacy(b *testing.B) { v := newLegacy(newBenchPerson()).Get("Address.City") b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = v.String() } } func BenchmarkAccessorStringNew(b *testing.B) { v := New(newBenchPerson()).Get("Address.City") b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchStr = v.String() } } func BenchmarkAccessorIntLegacy(b *testing.B) { v := newLegacy(newBenchPerson()).Get("Age") b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchInt = v.Int() } } func BenchmarkAccessorIntNew(b *testing.B) { v := New(newBenchPerson()).Get("Age") b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchInt = v.Int() } } // --------------------------------------------------------------------------- // 其它 API // --------------------------------------------------------------------------- func BenchmarkExistsLegacy(b *testing.B) { r := newLegacy(newBenchPerson()) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchBool = r.Exists("Address", "City") } } func BenchmarkExistsNew(b *testing.B) { r := New(newBenchPerson()) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchBool = r.Exists("Address", "City") } } func BenchmarkNewPtrLegacy(b *testing.B) { p := newBenchPerson() b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchR = newLegacy(p) } } func BenchmarkNewPtrNew(b *testing.B) { p := newBenchPerson() b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { benchR = New(p) } }