関連記事
GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ
概要
以下、自分用のメモです。忘れない内にメモメモ。。。
たまたまですが、以下の記事をみました。
最初にシングルトンパターンの説明があるのですが、以下のようなコードになってました。
上記記事より引用。
type Singleton struct { data string } var instance *Singleton func GetInstance() *Singleton { if instance == nil { instance = &Singleton{"Initial data"} } return instance }
見て、「ん?」ってなりました。これじゃスレッドセーフになってないです。
なので、複数のgoroutineが一気に入ってきたら場合によっては複数作れちゃうのでダメですね。
GetInstanceを呼び出した時に lazy でインスタンスを作成するのはよくやるやり方なので分かるのですが、ここをスレッドセーフにしないとシングルトンの意味が無くなります。
サンプル
個人的にシングルトンを使うことが最近無いのですが、Goの場合は以下のようにしています。
defines.go
シングルトン扱いで処理したい子です。
package defines import ( "sync" ) type ( Defines struct { def1 string def2 string } ) func (me *Defines) GetDef1() string { return me.def1 } func (me *Defines) GetDef2() string { return me.def2 } var ( instance *Defines once sync.Once ) func GetInstance() *Defines { once.Do(func() { instance = &Defines{ def1: "hello", def2: "world", } println("create: Defines") }) return instance }
インスタンスを作成する部分は sync.Once でガードしています。lazyな生成が必要ない場合は varでの宣言時に作っておけばオッケイ。
main.go
使う側。わざと複数のgoroutineで GetIntance() を呼び出すようにしています。
package main import ( "fmt" "runtime" "sync" "github.com/devlights/try-golang/examples/singleapp/designpatterns/singleton/defines" ) func main() { if err := run(); err != nil { panic(err) } } func run() error { type ( Singleton interface { GetDef1() string GetDef2() string } ) var ( c = runtime.NumCPU() l = make([]Singleton, 0, c) wg sync.WaitGroup ) wg.Add(c) for i := 0; i < c; i++ { go func() { defer wg.Done() println(">>> call: GetInstance") l = append(l, defines.GetInstance()) }() } wg.Wait() for i := 0; i < c; i++ { v := l[i] fmt.Printf("%p (%s:%s)\n", v, v.GetDef1(), v.GetDef2()) } return nil }
実行すると以下のようになります。
task: [default] go clean task: [default] go build task: [default] ./singleton >>> call: GetInstance create: Defines >>> call: GetInstance >>> call: GetInstance >>> call: GetInstance >>> call: GetInstance >>> call: GetInstance >>> call: GetInstance >>> call: GetInstance >>> call: GetInstance >>> call: GetInstance >>> call: GetInstance >>> call: GetInstance >>> call: GetInstance >>> call: GetInstance >>> call: GetInstance >>> call: GetInstance 0xc00007c020 (hello:world) 0xc00007c020 (hello:world) 0xc00007c020 (hello:world) 0xc00007c020 (hello:world) 0xc00007c020 (hello:world) 0xc00007c020 (hello:world) 0xc00007c020 (hello:world) 0xc00007c020 (hello:world) 0xc00007c020 (hello:world) 0xc00007c020 (hello:world) 0xc00007c020 (hello:world) 0xc00007c020 (hello:world) 0xc00007c020 (hello:world) 0xc00007c020 (hello:world) 0xc00007c020 (hello:world) 0xc00007c020 (hello:world)
参考情報
try-golang/examples/singleapp/designpatterns/singleton at main · devlights/try-golang · GitHub
Goのおすすめ書籍
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。