Skip to content

Commit 8d2379b

Browse files
committed
common/hreflect: Replace the map/RWMutex method cache with sync.Map
It's much faster when running in parallel: ``` GetMethodByName-10 125.1n ± 6% 181.7n ± 7% +45.30% (p=0.002 n=6) GetMethodByNamePara-10 770.10n ± 1% 24.77n ± 9% -96.78% (p=0.002 n=6) ```
1 parent 26d986f commit 8d2379b

File tree

2 files changed

+19
-16
lines changed

2 files changed

+19
-16
lines changed

Diff for: common/hreflect/helpers.go

+5-16
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,7 @@ type methodKey struct {
134134
name string
135135
}
136136

137-
type methods struct {
138-
sync.RWMutex
139-
cache map[methodKey]int
140-
}
141-
142-
var methodCache = &methods{cache: make(map[methodKey]int)}
137+
var methodCache sync.Map
143138

144139
// GetMethodByName is the same as reflect.Value.MethodByName, but it caches the
145140
// type lookup.
@@ -157,22 +152,16 @@ func GetMethodByName(v reflect.Value, name string) reflect.Value {
157152
// -1 if no such method exists.
158153
func GetMethodIndexByName(tp reflect.Type, name string) int {
159154
k := methodKey{tp, name}
160-
methodCache.RLock()
161-
index, found := methodCache.cache[k]
162-
methodCache.RUnlock()
155+
v, found := methodCache.Load(k)
163156
if found {
164-
return index
157+
return v.(int)
165158
}
166-
167-
methodCache.Lock()
168-
defer methodCache.Unlock()
169-
170159
m, ok := tp.MethodByName(name)
171-
index = m.Index
160+
index := m.Index
172161
if !ok {
173162
index = -1
174163
}
175-
methodCache.cache[k] = index
164+
methodCache.Store(k, index)
176165

177166
if !ok {
178167
return -1

Diff for: common/hreflect/helpers_test.go

+14
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,17 @@ func BenchmarkGetMethodByName(b *testing.B) {
134134
}
135135
}
136136
}
137+
138+
func BenchmarkGetMethodByNamePara(b *testing.B) {
139+
v := reflect.ValueOf(&testStruct{})
140+
methods := []string{"Method1", "Method2", "Method3", "Method4", "Method5"}
141+
142+
b.ResetTimer()
143+
b.RunParallel(func(pb *testing.PB) {
144+
for pb.Next() {
145+
for _, method := range methods {
146+
_ = GetMethodByName(v, method)
147+
}
148+
}
149+
})
150+
}

0 commit comments

Comments
 (0)