Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Singleton Pattern in Go (marcio.io)
134 points by mcastilho on July 12, 2015 | hide | past | favorite | 71 comments


It's funny how you can take an obvious antipattern (global variables) and turn it into a pattern by giving it a cool new name like "Singleton". In this spirit, I propose "the ProgramCounterAmbulator" as a cool new name for "goto."

Actually, gotos are usually less harmful than globals. At least they don't interfere with unit testing the way globals tend to.


No argument that Singletons make it difficult to unit test things but there are genuine cases where singletons are required: For instance, you don't want to end up creating multiple objects that read the configuration file, when one is enough. Or you certainly don't want to create too many objs that are heavy (like a cache that stores data heavy objects, or services, or god-objects (which are themselves an anti-pattern unavoidable in certain cases)).

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.


Depends on what you mean by "singleton". If you define it loosely as "a type of which there is only one instance", fine, no problem -- of course those will exist. But if you define it as "globally-accessible mutable state", then the problems start. Usually, the "singleton pattern" is explicitly a technique for doing the latter.

> 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...


Nailed it. It's fine to use a singleton, but don't call it from within every class you use it in. Just pass a reference to the instance of the singleton. Call it once in the outermost scope.


Just wondering what value the singleton provided if you only obtain it once. Isn't the purpose so you can obtain it whenever you want? If you just use a regular object, you run the risk of accidentally making another instance somewhere else, but you always have that risk with any regular object anyway.


It's kind of OK to use, as long as you don't call it all over the place and render your code untestable such that it can't be mocked out, but I'm not a huge fan of it. It's really a matter of opinion at that point.


I find that a better approach is to try and isolate pieces of code that needs access to specific resources, such as configuration files or standard output. Performing IO tasks, from every module in a code base, is an easy way to create very unmaintainable code.

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.


Any discussion of Singletons is incomplete without https://sites.google.com/site/steveyegge2/singleton-consider...


It’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 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.


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 thread-safe, used in a single-threaded context, or a pinless grenade.


There are exceptions to this rule--i.e. there are ways to not really be thread-safe but to have things work anyway--but they fall in the category of "you have to really, really know your CPU and be willing to write processor-specific code that just happens to work", so you can basically ignore them.

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.


An interesting exception is Lamport's Bakery:

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're only reading/writing from one thread, then locking/unlocking a mutex should have an extremely small overhead. So if you plan on having such a pattern available for use in multithreaded contexts, a mutex or some other thread-safe abstraction couldn't hurt.


You would have to use sync.Atomic for all reads and writes. If you just use normal reads and writes it's in violation of the Go language memory model. It might work for now or it might start a nuclear war. You never know.


Your "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.


+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 < 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.


Be careful with that benchmark. It's very vulnerable to SROA and constant propagation optimizing it away to nothing. (Doesn't look like Go's compiler optimizations are able to do that based on those numbers, but a modern optimizer will.)


Here's the mutex source: https://golang.org/src/sync/mutex.go . The fast path is just a CAS, which of course is going to be fast. But it's also important to know how it performs under contention.


This has no contention and is essentially a no-op? Or do I not understand go?


It is a no-op, but Golang's Plan 9-based compilers don't do much optimization, so they aren't able to eliminate it.


Try again with many goroutines trying to lock/unlock in parallel (and GOMAXPROCS>1), the results are quite different!


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)


A few years ago, the C++ standard didn't guarantee that the double-checked idiom would work. Even if your threading library had some way to insert the necessary memory barriers, it was possible that your compiler would optimize important things away.

C++11 changes that. The language now has standard ways to add memory barriers, and compiler optimizations can't remove them.


Yes, this is broken on certain architectures like PPC. Another core may see the "check" bool as set, but the fields of the protected object as uninitialized. One way to address this is to insert a write barrier just before setting the check bool, and a read barrier just after reading it.


In modern Java, it's easy enough if you've been shown the pattern. What's hard is understanding/discovering it from first principles.


Someone apparently disliked this comment, but check out

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.


You should use enums for singletons i Java. Simple to write, threadsafe and handles serialization. All with guarantees from the Java language specification.


I wasn't actually talking about singletons, just the doublechecked locking pattern. It's also necessary for laziness on objects that are referenced by multiple threads.

I tend to think Singletons are a dubious design pattern, like a lot of other people.


This is cute, but I think (someone will correct me if I'm wrong) that the real idiom is: things that would be singletons in Java are instead servers managing a channel in Golang.


Why incur the cost and complexity of a channel if what you are doing doesn't require it? Go's sync.Once just implements the check-lock-check pattern. It doesn't use a channel in the background.

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.]


The architecture! Not the design of this singleton.


The beauty of Go's channel design approach is how it isolates responsibilities. It's not just about synchronization. A great example is Rob Pike's lexer.

When passing singletons around, you are communicating with shared state. Sometimes, there is no way around it.


I 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.


Shouldn't there be a disclaimer though?

Or, at least an example of when it would be a good idea to use a singleton over some other pattern?


Singletons are useful and wide spread concepts. What is an anti pattern is implementing them in a way that's not thread safe (which is made worse if your singleton is mutable).

Letting DI frameworks handle your singletons is the best way to get the best of both worlds.


No no, singletons are pathological liars http://misko.hevery.com/2008/08/17/singletons-are-pathologic...

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.


This post is chock-full of antipatterns. Both the singleton pattern and double checked locking should be avoided.


Yea it's easy enough to use dependency injection to satisfy these supposedly "global" requirements. About the only global state I can tolerate is read-only constants, but even then you are much better off with DI just because of testing.


How do handle configuration? Your program starts up, generates some settings, then those need to be shared across all threads to avoid incurring the cost of regenerating during every call to a function.


But in that case config values are to be treated as constants (read only). You don't have concurrency issues for code that doesn't change.


DI is an antipattern.


who told you that? you'd better not listen to that guy anymore.


What are better alternatives? Service locator?


What's the point of a singleton when you can just have variables in an anonymous struct at root level, and functions defined at root as well?

  var server struct {
  	host string
  	port string
  }
  
  func serverStart() {
  	server.host = "..."
  	server.port = "..."
  }


When do you call "serverStart()"? If the answer is "eagerly during startup", there's no problem (other than startup time, of course). If the answer is "on demand", now you have a synchronization problem.


Because there are many ways to solve a problem.


Wouldn't it make more sense to have some sort of manager that receives information on an incoming channel, manages the state internally, and reports out on an outgoing channel?


Abstractly, if you somehow need a singleton object, this will be substantially faster if you need it frequently. And if you're careful to do all the other things you need to do in order to make this work and safe, as seen in the other messages in this post.

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.


A singleton is basically a global variable and those aren't really important to "shim" in Go. Object method calls are pretty much the same conceptually as message passing but when you actually need to synchronize as you point out goroutines and channels make things much simpler. I think what this post was going for wasn't "use singletons", it was "look at these interesting threading issues that arise and how we address them in (non idiomatic) Go"


There's more that needs to be done if the goal is "look at these interesting threading issues that arise and how we address them in (non idiomatic) Go", because the initialization described in the post is broken.

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.


This seems more idiomatic:

  func init() {
      instance = &singleton{}
  }


If instance can truly be initialized like that, then there's no need for the init() function, just do it at the top level:

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.


> There may possibly be a problem with unnecessarily slowing startup times in the case you don't need the singleton - in which case, profiling will tell you and you can revert to the method in the blog post.

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.


There's a package for this, if anyone needs this pattern off the shelf: https://github.com/dropbox/godropbox/tree/master/singleton


Isn't Singleton's really an anti-pattern? SO discussions here: http://stackoverflow.com/questions/137975/what-is-so-bad-abo...


[deleted]


C++11 did make it possible to write portable correct double-checked locking, but it's still very easy to get it wrong (unless you can get away with just using std::call_once).


Coding Pro Tip: Instead of using the Singleton pattern, make one instance of your class at the start of your program and pass it around to its users.

Singletons are really just as bad as global variables. Why? Because they are global variables.


Depending on what you are trying to implement - passing an extra variable everywhere is just creating noise (because potentially you have to have an extra parameter to EVERY function or method). I believe in KISS - everything should be as simple as possible but not simpler. Believe it or not there are valid uses for a Singleton which, many would agree, include a simple logging class [1].

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...


> you have to have an extra parameter to EVERY function or method

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.


> because potentially you have to have an extra parameter to EVERY function or method

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.


I agree,

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).


I'm not sure how... pass it around is 'better' than global scope. Meaning not sure what problems you're avoiding here. If the scope is a single thread, no problem. If it's accessed from multiple threads, you have problems whether it's a global, singleton, or passed by reference.

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.


> I'm not sure how... pass it around is 'better' than global scope.

- 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...


>Singletons are really just as bad as global variables. Why? Because they are global variables.

And just as handy as global variables.


> And just as handy as global variables.

which means not really handy in a non-thread safe context.


Two things:

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.


Why not use an atomic compare-and-swap instruction as offered by all of the major underlying hardware architectures?


Oh no.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: