mirror of
https://github.com/peco/peco.git
synced 2026-09-10 07:16:29 -04:00
fix: merge two context keys into one in Hub.Batch
Reduce context.WithValue calls from 2 to 1 per Batch invocation. | Metric | Before | After | Delta | |------------|--------|-------|-------| | allocs/op | 3 | 2 | -1 | | B/op | 128 | 80 | -48 | | ns/op | ~372 | ~352 | -5% |
This commit is contained in:
parent
6869d4dcfa
commit
e2bc390c68
29
hub/bench_test.go
Normal file
29
hub/bench_test.go
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package hub_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/peco/peco/hub"
|
||||
)
|
||||
|
||||
// BenchmarkHubBatch measures the allocation cost of Hub.Batch context setup.
|
||||
func BenchmarkHubBatch(b *testing.B) {
|
||||
h := hub.New(5)
|
||||
ctx := context.Background()
|
||||
|
||||
// Drain query channel and call Done() so batch sends unblock
|
||||
go func() {
|
||||
for p := range h.QueryCh() {
|
||||
p.Done()
|
||||
}
|
||||
}()
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for b.Loop() {
|
||||
h.Batch(ctx, func(bctx context.Context) {
|
||||
h.SendQuery(bctx, "test")
|
||||
})
|
||||
}
|
||||
}
|
||||
22
hub/hub.go
22
hub/hub.go
|
|
@ -70,17 +70,16 @@ func New(bufsiz int) *Hub {
|
|||
}
|
||||
}
|
||||
|
||||
type batchPayloadKey struct{}
|
||||
|
||||
// batchLockKey is used to detect re-entrant Batch calls so that
|
||||
// nested calls skip mutex acquisition and avoid deadlock.
|
||||
type batchLockKey struct{}
|
||||
// batchCtxKey is a single context key that signals both "this is a batch
|
||||
// payload" and "the hub mutex is already held" for re-entrant detection.
|
||||
// Using one key instead of two avoids a second context.WithValue allocation.
|
||||
type batchCtxKey struct{}
|
||||
|
||||
// Batch allows you to synchronously send messages during the
|
||||
// scope of f() being executed. The mutex is acquired automatically
|
||||
// unless this is a nested Batch call (detected via context).
|
||||
func (h *Hub) Batch(ctx context.Context, f func(ctx context.Context)) {
|
||||
nested, _ := ctx.Value(batchLockKey{}).(bool)
|
||||
nested, _ := ctx.Value(batchCtxKey{}).(bool)
|
||||
|
||||
if pdebug.Enabled {
|
||||
g := pdebug.Marker("Batch (nested=%t)", nested)
|
||||
|
|
@ -102,8 +101,7 @@ func (h *Hub) Batch(ctx context.Context, f func(ctx context.Context)) {
|
|||
}
|
||||
}()
|
||||
|
||||
batchCtx := context.WithValue(ctx, batchPayloadKey{}, true)
|
||||
batchCtx = context.WithValue(batchCtx, batchLockKey{}, true)
|
||||
batchCtx := context.WithValue(ctx, batchCtxKey{}, true)
|
||||
f(batchCtx)
|
||||
}
|
||||
|
||||
|
|
@ -132,12 +130,8 @@ func (p *Payload[T]) waitDone() {
|
|||
|
||||
// isBatchCtx reports whether the context was created by a Batch call.
|
||||
func isBatchCtx(ctx context.Context) bool {
|
||||
var isBatchMode bool
|
||||
v := ctx.Value(batchPayloadKey{})
|
||||
if vv, ok := v.(bool); ok {
|
||||
isBatchMode = vv
|
||||
}
|
||||
return isBatchMode
|
||||
v, _ := ctx.Value(batchCtxKey{}).(bool)
|
||||
return v
|
||||
}
|
||||
|
||||
// send is the low-level generic utility for sending typed payloads.
|
||||
|
|
|
|||
Loading…
Reference in a new issue