From 93dde6b0e6c0de50a47f9dc5f3ac7205c36742aa Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Tue, 28 Jun 2011 09:43:01 -0400 Subject: [PATCH] sync: add fast path to Once The implementation does not grab the lock, if Once is already initalized. Benchmark results on HP Z600 (2 x Xeon E5620, 8 HT cores, 2.40GHz) are as follows: benchmark old ns/op new ns/op delta sync_test.BenchmarkOnce 187.00 14.00 -92.51% sync_test.BenchmarkOnce-2 909.00 21.40 -97.65% sync_test.BenchmarkOnce-4 3684.00 20.90 -99.43% sync_test.BenchmarkOnce-8 5987.00 23.00 -99.62% sync_test.BenchmarkOnce-16 5051.00 21.60 -99.57% R=bradfitz, rsc CC=golang-dev https://golang.org/cl/4641066 --- src/pkg/sync/once.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/pkg/sync/once.go b/src/pkg/sync/once.go index b6f5f5a8726..447b71dcb7a 100644 --- a/src/pkg/sync/once.go +++ b/src/pkg/sync/once.go @@ -4,10 +4,14 @@ package sync +import ( + "sync/atomic" +) + // Once is an object that will perform exactly one action. type Once struct { m Mutex - done bool + done int32 } // Do calls the function f if and only if the method is being called for the @@ -26,10 +30,14 @@ type Once struct { // Do to be called, it will deadlock. // func (o *Once) Do(f func()) { + if atomic.AddInt32(&o.done, 0) == 1 { + return + } + // Slow-path. o.m.Lock() defer o.m.Unlock() - if !o.done { - o.done = true + if o.done == 0 { f() + atomic.CompareAndSwapInt32(&o.done, 0, 1) } }