]> Cypherpunks repositories - gostls13.git/commitdiff
sync: add fast path to Once
authorDmitriy Vyukov <dvyukov@google.com>
Tue, 28 Jun 2011 13:43:01 +0000 (09:43 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 28 Jun 2011 13:43:01 +0000 (09:43 -0400)
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

index b6f5f5a87264346c264025e1e0496716ac73f8a2..447b71dcb7af289ffb80f836fd9e2cd71f546464 100644 (file)
@@ -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)
        }
 }