Singleton Pattern in Go
41–50 of 76 posts
Re: Singleton Pattern in Go
#42Earlier quoted context omitted.
Totally! I was going to post the same thing. Double-checked locking is either impossible or really hard to get right, depending on the language and architecture's guarantees! 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.
On C++ if we're using a bool as the "check" and pthread_mutex_lock on a regular mutex would that work, or do we still need to hardcode fences? (Asking because this pattern is used by libcxxabi code)
Re: Singleton Pattern in Go
#43Your "check-lock-check" code is probably broken (depending on the intricacies of Golang's memory model). If the compiler or CPU reorders any stores to the fields of "instance" after the assignment to "instance" itself, other threads could start working with a partially uninitialized object. Once() uses atomics on the fast path for a reason.
Totally! I was going to post the same thing. Double-checked locking is either impossible or really hard to get right, depending on the language and architecture's guarantees! 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
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.
Re: Singleton Pattern in Go
#44Re: Singleton Pattern in Go
#45It’s worth noting that not only do you need to synchronize access to the singleton, you need to synchronize access to the singleton’s state as well. And even if you manage that at a fine-grained layer, you’re still setting yourself up for all the problems associated with singletons: http://c2.com/cgi/wiki?SingletonsAreEvil . If you have a bunch of immutable state, then build unexported package variables in the packag…
Do you think it would be fine to use a singleton if the writes are all happening in a single thread and it's not critical that the reads be synchronized? Sharing state across go routines seems like something to be avoided. In vanilla Java it's always not easy to avoid sharing state.
Re: Singleton Pattern in Go
#46Earlier quoted context omitted.
Do you think it would be fine to use a singleton if the writes are all happening in a single thread and it's not critical that the reads be synchronized? Sharing state across go routines seems like something to be avoided. In vanilla Java it's always not easy to avoid sharing state.
If you want your reads to ever work, then they need to be synchronized. Reading from an unfenced address during concurrent writes is undefined behavior for any CPU architecture you can think of, which means you’ll get stale reads _in a best-case scenario_. You can also get garbage reads (e.g. as your CPU interprets your read of a 64-bit pointer as two 32-bit reads), crashes, bees, etc. The code you write is either th…
My favorite is the libdispatch abuse of cpuid to flood the pipeline on Intel CPUs for this problem: https://www.mikeash.com/pyblog/friday-qa-2014-06-06-secrets-...
But really, take Coda's advice. If you aren't synchronizing your reads, you can basically just assume your code is broken.
Re: Singleton Pattern in Go
#47Earlier quoted context omitted.
Totally! I was going to post the same thing. Double-checked locking is either impossible or really hard to get right, depending on the language and architecture's guarantees! 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.
+1 for the aggressive approach, mutexes are very fast in go. 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 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 MacBo…
Re: Singleton Pattern in Go
#48Earlier quoted context omitted.
Totally! I was going to post the same thing. Double-checked locking is either impossible or really hard to get right, depending on the language and architecture's guarantees! 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.
+1 for the aggressive approach, mutexes are very fast in go. 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 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 MacBo…
Re: Singleton Pattern in Go
#49Earlier quoted context omitted.
Totally! I was going to post the same thing. Double-checked locking is either impossible or really hard to get right, depending on the language and architecture's guarantees! 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.
+1 for the aggressive approach, mutexes are very fast in go. 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 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 MacBo…
Re: Singleton Pattern in Go
#50I thought there was a lot of literature pretty convincingly arguing that singleton is in fact an anti-pattern.
There is, singletons are an anti-pattern, they're still interesting to discuss like this in terms of making them safe. In a language with both concurrency primitives and globals singletons have little (no) place anyway. I still learned from the post.
Or, at least an example of when it would be a good idea to use a singleton over some other pattern?