diff --git a/private/registry/registry.go b/private/registry/registry.go index d5ddbef..f5579a7 100644 --- a/private/registry/registry.go +++ b/private/registry/registry.go @@ -108,9 +108,8 @@ func (r *serviceRegistry) ServiceCount() int { func (r *serviceRegistry) ForEachService(cb func(protoreflect.ServiceDescriptor) bool) { r.lock.RLock() - services := r.services - r.lock.RUnlock() - for _, service := range services { + defer r.lock.RUnlock() + for _, service := range r.services { if !cb(service) { break } diff --git a/private/registry/registry_bench_test.go b/private/registry/registry_bench_test.go new file mode 100644 index 0000000..0e34c31 --- /dev/null +++ b/private/registry/registry_bench_test.go @@ -0,0 +1,83 @@ +package registry + +import ( + "fmt" + "testing" + "google.golang.org/protobuf/reflect/protoreflect" +) + +// A dummy service descriptor +type dummyServiceDescriptor struct { + protoreflect.ServiceDescriptor + name protoreflect.FullName +} + +func (d dummyServiceDescriptor) FullName() protoreflect.FullName { + return d.name +} + +func BenchmarkForEachService_Current(b *testing.B) { + r, err := NewServiceRegistry() + if err != nil { + b.Fatal(err) + } + + for i := 0; i < 1000; i++ { + r.addService(dummyServiceDescriptor{name: protoreflect.FullName(fmt.Sprintf("service_%d", i))}) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + r.ForEachService(func(sd protoreflect.ServiceDescriptor) bool { + return true + }) + } +} + +func BenchmarkForEachService_InsideRLock(b *testing.B) { + r, err := NewServiceRegistry() + if err != nil { + b.Fatal(err) + } + + for i := 0; i < 1000; i++ { + r.addService(dummyServiceDescriptor{name: protoreflect.FullName(fmt.Sprintf("service_%d", i))}) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + r.lock.RLock() + for range r.services { + if !true { + break + } + } + r.lock.RUnlock() + } +} + +func BenchmarkForEachService_Slice(b *testing.B) { + r, err := NewServiceRegistry() + if err != nil { + b.Fatal(err) + } + + for i := 0; i < 1000; i++ { + r.addService(dummyServiceDescriptor{name: protoreflect.FullName(fmt.Sprintf("service_%d", i))}) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + r.lock.RLock() + services := make([]protoreflect.ServiceDescriptor, 0, len(r.services)) + for _, s := range r.services { + services = append(services, s) + } + r.lock.RUnlock() + for range services { + if !true { + break + } + } + } +}