Dwarves
Memo
Type ESC to close search bar

A tour of Singleton design pattern with Golang

Problem

Just imagine we need to build a simple web page to show live subscribers of a Youtube channel. Main object here is “subscriber” so we need a tool (counter) to update number of subscribers in real-time.

There are 2 actors: subscribers (Youtube) and visitors (our web page)

When a user subscribes to a channel, we update the counter by +1. And we do the same for other incoming subscribers, but there are 2 things we have to keep in mind:

Singleton Overview

Singleton is one of Creational design patterns. It has some characteristics:

What does Singleton resolve?

Back to our above analogy with subscription counter, we can use Singleton to instatiate the counter and provide its global access.

Applicability

Use Singleton when you need to manage one & only instance of a resource (e.g. configuration, logger, etc.)

Approaches

There are 2 ways to implement Singleton pattern:

EagerLazy
Initialize the instance as soon as your app is startedInitialize the instance as the first time it is requested (e.g. the counter is only instantiated when the first subscription is made)
Should only be applied to light-weight resource since it will take a lot of compute power at the beginning and reduce the app performanceShould not be applied to heavy-size resource since it will unnecessary take a lot of compute power at the beginning and reduce the app performance
Simple to implement, don't have to worry about race conditionMore complex implementation, need to make sure the instantiation is thread-safe to avoid creating redundant instances

Pseudocode (golang)

First, define counter struct

type counter struct {
	views int
}

Eager initialization

var instance *counter = &counter{}

func getCounter() *counter {
	return instance
}

Lazy initialization: use double-checked locking mechanism to avoid unnecessary lock when the instance has already been initialized

var instance *counter

func getCounter() *counter {
	// instance has not been initialized
	if instance == nil {
		// lock to avoid multiple instances are created simultaneously by multi threads
		lock.Lock()
		defer lock.Unlock()

		// need to recheck because first check can be passed by multiple gorountines
		if instance == nil {
			instance = &counter{}
		}
	}

	// when instance has already been initialized -> return
	return instance
}

Benefits & Drawbacks

Benefits
You can assure that the class/type has only one instance if the implementation is done properly.

Drawbacks

References