If you must use a singleton, I'd really recommend doing the so-called "aggressive" approach, which should have really been named the "actually won't crash sometimes" approach.
If you must use a singleton, I'd really recommend doing the so-called "aggressive" approach, which should have really been named the "actually won't crash sometimes" approach.
I got curious and wrote a quick little benchmark test:
$ cat bench_test.go
package main
import (
"sync"
"testing"
)
func BenchmarkMutex(b *testing.B) {
var m sync.Mutex
for n := 0; n < b.N; n++ {
m.Lock()
m.Unlock()
}
}
$ go test -v -bench=. bench_test.go
BenchmarkMutex 50000000 24.0 ns/op
ok command-line-arguments 1.235s
A set of mutex.Lock() & .Unlock() calls takes only 24.0ns on average to complete.Thus it's possible to lock/unlock more than 41 million times per second on the puny 2011 MacBook Air I used for this.
My .02c:
The post seems like a case of premature optimization.
Resource bottlenecks due to too much mutex locking in go does not seem like a case that will be commonly hit.
With infinite potential bottlenecks, I don't like to spend my time worrying and fussing over things that are:
A) Not yet a problem.
B) Unlikely to ever be a problem or give me grief.
Worrying about the overhead cost of locking falls squarely into just such a category.
(Asking because this pattern is used by libcxxabi code)
C++11 changes that. The language now has standard ways to add memory barriers, and compiler optimizations can't remove them.
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLo.... Scroll down to "Fixing Double-Checked Locking using Volatile." It's five lines of code without braces, and can be applied without any creativity or reasoning.
I tend to think Singletons are a dubious design pattern, like a lot of other people.