笔记

代码实现

单例模式采用了 饿汉式 和 懒汉式 两种实现,个人其实更倾向于饿汉式的实现,简单,并且可以将问题及早暴露,懒汉式虽然支持延迟加载,但是这只是把冷启动时间放到了第一次使用的时候,并没有本质上解决问题,并且为了实现懒汉式还不可避免的需要加锁。

饿汉式

代码实现:

package singleton

// Singleton 饿汉式单例
type Singleton struct{}

var singleton *Singleton

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

// GetInstance 获取实例
func GetInstance() *Singleton {
	return singleton
}

单元测试:

package singleton_test

import (
	singleton "github.com/mohuishou/go-design-pattern/01_singleton"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestGetInstance(t *testing.T) {
	assert.Equal(t, singleton.GetInstance(), singleton.GetInstance())
}

func BenchmarkGetInstanceParallel(b *testing.B) {
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			assert.Equal(b, singleton.GetInstance(), singleton.GetInstance())
		}
	})
}

懒汉式(双重检测)

代码实现:

package singleton

import "sync"

var (
	lazySingleton *Singleton
	once          = &sync.Once{}
)

// GetLazyInstance 懒汉式
func GetLazyInstance() *Singleton {
	if lazySingleton == nil {
		once.Do(func() {
			lazySingleton = &Singleton{}
		})
	}
	return lazySingleton
}

单元测试:

package singleton_test

import (
	"testing"

	singleton "github.com/mohuishou/go-design-pattern/01_singleton"

	"github.com/stretchr/testify/assert"
)

func TestGetLazyInstance(t *testing.T) {
	assert.Equal(t, singleton.GetLazyInstance(), singleton.GetLazyInstance())
}

func BenchmarkGetLazyInstanceParallel(b *testing.B) {
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			assert.Equal(b, singleton.GetLazyInstance(), singleton.GetLazyInstance())
		}
	})
}

测试结果

可以看到在这两种的性能其实差不多

goos: darwin
goarch: amd64
pkg: github.com/mohuishou/go-design-pattern/01_singleton
BenchmarkGetLazyInstanceParallel
BenchmarkGetLazyInstanceParallel-8   	 1248008	       955 ns/op
BenchmarkGetInstanceParallel
BenchmarkGetInstanceParallel-8       	 1268222	       945 ns/op
PASS