diff --git a/core/errorx/atomicerror.go b/core/errorx/atomicerror.go index 76f874e5..d885f489 100644 --- a/core/errorx/atomicerror.go +++ b/core/errorx/atomicerror.go @@ -1,21 +1,18 @@ package errorx -import "sync" +import "sync/atomic" type AtomicError struct { - err error - lock sync.Mutex + err atomic.Value // error } func (ae *AtomicError) Set(err error) { - ae.lock.Lock() - ae.err = err - ae.lock.Unlock() + ae.err.Store(err) } func (ae *AtomicError) Load() error { - ae.lock.Lock() - err := ae.err - ae.lock.Unlock() - return err + if v := ae.err.Load(); v != nil { + return v.(error) + } + return nil } diff --git a/core/errorx/atomicerror_test.go b/core/errorx/atomicerror_test.go index fa19cdb2..d05f8866 100644 --- a/core/errorx/atomicerror_test.go +++ b/core/errorx/atomicerror_test.go @@ -2,6 +2,8 @@ package errorx import ( "errors" + "sync" + "sync/atomic" "testing" "github.com/stretchr/testify/assert" @@ -19,3 +21,53 @@ func TestAtomicErrorNil(t *testing.T) { var err AtomicError assert.Nil(t, err.Load()) } + +func BenchmarkAtomicError(b *testing.B) { + var aerr AtomicError + wg := sync.WaitGroup{} + + b.Run("Load", func(b *testing.B) { + var done uint32 + go func() { + for { + if atomic.LoadUint32(&done) != 0 { + break + } + wg.Add(1) + go func() { + aerr.Set(errDummy) + wg.Done() + }() + } + }() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = aerr.Load() + } + b.StopTimer() + atomic.StoreUint32(&done, 1) + wg.Wait() + }) + b.Run("Set", func(b *testing.B) { + var done uint32 + go func() { + for { + if atomic.LoadUint32(&done) != 0 { + break + } + wg.Add(1) + go func() { + _ = aerr.Load() + wg.Done() + }() + } + }() + b.ResetTimer() + for i := 0; i < b.N; i++ { + aerr.Set(errDummy) + } + b.StopTimer() + atomic.StoreUint32(&done, 1) + wg.Wait() + }) +}