Singleton Pattern in Go
marcio.io
marcio.io
Actually, gotos are usually less harmful than globals. At least they don't interfere with unit testing the way globals tend to.
At times, there's genuinely only a single entity of "x" that's available for use by the environment, like a security-policy, or access to standard-output, and so on...
Singletons are necessary evil, IMO.
Re: Global state: At some point the abstraction will have to leak. If you squint enough, nothing is truly isolated, and everything's sharing everything else with other binaries on any given system at some abstraction level or the other. This is more often the reason why security-exploits are theoretically possible despite isolation.
Of course this is all a tradeoff with other code structuring ideals. Programming languages with Monads tend to be very good at isolating such things.
> For instance, you don't want to end up creating multiple objects that read the configuration file, when one is enough.
Sure. But that doesn't mean the config file reader has to be globally-accessible. Instead, try allocating it on the stack in your main() function, then passing the object into each component that needs to see it. Better yet, only pass each component a sub-object(s) of the config which applies specifically to that component.
Now you have a bunch of useful benefits:
- Readability: You can clearly see and follow what components are affected by what parts of the config file.
- Testability: Unit tests can easily provide a test configuration.
- Maintainability: If some day you realize that you need to create two instances of some component and configure them differently, it's easy to do that without rewriting tons of code or introducing horrible "namespacing" hacks.
- Security: If your config file contains anything sensitive (say, database credentials), it's no longer the case that every damned module in the whole system has the ability to read those secrets. In fact, if your language is memory-safe and bans mutable global state, you can trivially sandbox any piece of code by simply not passing it references to anything it shouldn't be able to access. (This is called "capability-based security" or "object capabilities", and it works.)
Extended argument (which I wrote many years ago...):
http://www.object-oriented-security.org/lets-argue/singleton...
If you have a bunch of immutable state, then build unexported package variables in the package’s `init` func and export funcs which use those variables.
If you have a bunch of mutable state, then don’t use a singleton.
The code you write is either thread-safe, used in a single-threaded context, or a pinless grenade.
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.
https://en.m.wikipedia.org/wiki/Lamport%27s_bakery_algorithm
Thread safety without synchronisation primitives. I'm not sure it's ever actually a good idea to use it, though.
EDIT: unless you count a fence as a synchronisation primitive.
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.
(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.
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.
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.
In fact, it is better to use sync.Once to reduce the risk getting the semantics of check-lock-check incorrect. :)
[edit: It occurred to me that the parent may be speaking about architecture and not about the singleton's design. From an architectural perspective, there are much better patterns in golang than a singleton.]
When passing singletons around, you are communicating with shared state. Sometimes, there is no way around it.
Or, at least an example of when it would be a good idea to use a singleton over some other pattern?
Letting DI frameworks handle your singletons is the best way to get the best of both worlds.
Atomic mutable global state is still mutable global state. DI containers mean you don't need a singleton but can just create a single instance which lets you scope it and does not mix lifetime duration and object properties.
var server struct {
host string
port string
}
func serverStart() {
server.host = "..."
server.port = "..."
}Practically, all the examples I've ever of why you'd ever want a singleton are indeed better done as a goroutine server over channels. Within the object you get an implicit lock by virtue of being the only goroutine ever to touch that stuff, and as long as you don't need this object to use more than one CPU total and the overhead of channels isn't a big deal, which again, describes the vast bulk of cases I've ever heard of that call for singletons, it's a better way to go.
And I'd note I've written a couple dozen different goroutine server things and a grand total of 0 'singletons', so... yeah.
If I had an immutable singleton object that was somehow very expensive to initialize, I might consider this approach. Not sure when that would come up but I'm sure it describes something.
Shared-memory multithreading is hard. Golang does not do much to prevent you from shooting yourself in the foot here, as this post proves. So use the abstractions wherever possible. In this case, Once correctly performs the atomics, and naive double-checked locking doesn't.
func init() {
instance = &singleton{}
}var instance = &singleton{}
In fact, a lot of idiomatic Go will ignore the Get() method, exporting the instance itself:
var Instance = &singleton{}
Clearly if you overwrite it, bad things will happen. Don't do that.
There may possibly be a problem with unnecessarily slowing startup times in the case you don't need the singleton and initialization is more complicated than a malloc - in which case, profiling will tell you and you can revert to the method in the blog post.
Remember that Go's strict import/dependency requirements mean you're unlikely to import the package (and trigger the initialization) unless you actually use the singleton.
It is non-idiomatic to use the sync.atomic package.
Not just in that case. If you lazily initialize then you can get other things done before—or while—you're waiting for the singleton constructor to run. Global constructors are suboptimal for performance almost as a rule.
Singletons are really just as bad as global variables. Why? Because they are global variables.
And just as handy as global variables.
which means not really handy in a non-thread safe context.
One could argue that you could just create it in the section of code you want to log - but that just creates noise and you end up repeating code.
logger = Log() # run code to open the file to the last position logger.log("test")
vs
Log.instance().log("test")
Now imagine this was a multi-threaded application - singleton arguments are much different.
> Singletons are really just as bad as global variables. Why? Because they are global variables.
Everyone has their own opinions - but you can't make sweeping generalizations. I'm not saying a global variable is appropriate in every situation - but every language, and project, is different. There are even different dialects of C++ [2].
[1] - http://stackoverflow.com/questions/228164/on-design-patterns...
[2] - http://www.reddit.com/r/programming/comments/197dn1/introduc...
Dependency injection provides a pretty good solution to this, potentially even for the logging use case. Classes (or code modules or whatever) only need to think about their direct dependencies, and indirect dependencies are handled naturally by the wiring code. In a well-written codebase using DI, you basically never need to write code that accepts an argument just so that it can pass that argument down to other code.
For example, if a class Foo deep in your program wants to use an interface called Logger for the first time, you just add a Logger as a field and pass the Logger into the Foo constructor in your wiring code. It's a little more ceremony than an import statement, but not by much, especially if you use a DI framework to do the wiring for you. Importantly, you don't need to make any changes to code that uses Foo.
An advantage to this approach is that it makes it easier to test usage of Logger (e.g. asserting that Foo logs an error in a particular situation). It also makes it easier to extend the Logger, like using a Logger wrapper that collects statistics on what was logged, without needing a special extensibility point in the Logger implementation.
That's not to say globals/singletons are always a bad idea. They tend to result in shorter code and they're easier to understand, and you can still test against them if you're willing to use mutable singletons (e.g. monkey patching in Python) or custom extensibility points. My main point is that, if you have a class that's useful in a wide variety of situations, there are other solutions than just "use a global" and "explicitly pass it around everywhere", and IMO dependency injection is one of the best options if you're writing serious code.
More often you have an extra parameter to class constructors, not every method. It's really not that bad, even when you choose to do it manually (as I do) rather than use a dependency injection framework.
> I believe in KISS - everything should be as simple as possible but not simpler.
I agree, which is why I avoid singletons because while they appear to reduce complexity in the short term they add horrendous amounts of complexity in the long term.
Not actually completely true, you can still have races in single threaded code. Consider two state variables that are effected by a shared variable. Not hard to have the two state variables in disagreement over the shape of the world.
- Readability: You can see what components use the thing by following the variable as it is passed around.
- Testability: Tests can pass in a mock thing.
- Maintainability: If you discover someday that you need two different instances of the thing to pass into two different subsystems, you can do that. (This happens a lot, and programmers are really bad at foreseeing it.)
- Security: Only the components to which you've passed the thing can possibly use it (subject to the memory safety guarantees of your language).
http://www.object-oriented-security.org/lets-argue/singleton...
everybody user a Singleton some time in his life: cause it is often user as first pattern learned and also cause it is a quick and dirty workaround to fix Your code, For onstance to have a single connection handle to a database, instead of review your class diagram (if any).
1) Unless you've explicitly checked that Go's memory model prevents read/write moves to allow double-checked locking, don't do it.
2) The pattern is usually a CAS after the check.