Edited at

sync.Onceの挙動がなんとなくしか分からなかったので実際に試してみた

More than 1 year has passed since last update.


sync.Onceとは

syncパッケージの処理はこちらで説明されてたので、ご参考までにどうぞ

https://qiita.com/t-mochizuki/items/80dc959b4221c53f3c40#synconce


実際に試してみた


PatternA

とりあえずsync.Onceを使った場合と使わない場合を織り交ぜてみた


テストコード

package main

import "fmt"
import "sync"

var foo string

func main() {
var once sync.Once

once.Do(func() {
foo = "A"
})
once.Do(func() {
foo = "B"
})
fmt.Println(foo)
foo = "C"
fmt.Println(foo)
once.Do(func() {
foo = "D"
})
fmt.Println(foo)
}

https://play.golang.org/p/imWwk2ij84-


結果

A

C
C


PatternB

PatternAで fooD にかわらなかったのが、C が代入されていたからか、そのまえにsync.Onceを使っていたからかを切り分ける


テストコード

package main

import "fmt"
import "sync"

var foo string

func main() {
var once sync.Once

foo = "C"
once.Do(func() {
foo = "D"
})
fmt.Println(foo)
}

https://play.golang.org/p/q2-qO73J7L1


結果

D


PatternC

異なる処理を同じ sync.Once を使った場合にどうなるかを確認


テストコード

package main

import "fmt"
import "sync"

var foo string
var bar string

func main() {
var once sync.Once

foo = "NoN"
bar = "NoN"
once.Do(func() {
foo = "A"
})
once.Do(func() {
bar = "B"
})
fmt.Printf("foo: %s\n",foo)
fmt.Printf("bar: %s\n",bar)
}

https://play.golang.org/p/A4Uq4yUUhUe


結果

foo: A

bar: NoN


PatternD

異なる処理を異なる sync.Once を使った場合にどうなるかを確認


テストコード

package main

import "fmt"
import "sync"

var foo string
var bar string

func main() {
var typea sync.Once
var typeb sync.Once

foo = "NoN"
bar = "NoN"
typea.Do(func() {
foo = "A"
})
typeb.Do(func() {
bar = "B"
})
fmt.Printf("foo: %s\n",foo)
fmt.Printf("bar: %s\n",bar)
}

https://play.golang.org/p/VYXifllWJyy


結果

foo: A

bar: B


結論


  • sync.Onceは宣言した変数別に管理される

  • 中の処理が異なっていても関係ない。異なる処理を同じSync.Onceで管理してはいけない

当然といったら当然な結果でした。