ð èæ¯ç¥èïŒèªãã§ããåé¡ãžïŒ
Day 013-014ã§sync.Mutex/sync.RWMutexã䜿ã£ããå
±æç¶æ
ã®æä»å¶åŸ¡ããåŠã³ãŸãããä»ååŠã¶sync.Onceãšsync.Poolã¯ãã©ã¡ããsyncããã±ãŒãžã®äžéšã§ãããMutexãšã¯éããæä»å¶åŸ¡ãã®ãã®ããç®çã§ã¯ãããŸãããããããç¹å®ã®äžŠè¡åŠçã·ããªãªã«ç¹åããéå
·ã§ãã
sync.Once: ãåæååŠçããäœååŒã°ããŠãã»äœåã®goroutineããåæã«åŒã°ããŠããå¿
ã1åã ãå®è¡ãããããã®ããªããã£ãã§ããå
žåçã«ã¯ãã·ã³ã°ã«ãã³ã®çæã»èšå®ãã¡ã€ã«ã®èªã¿èŸŒã¿ã»ã³ãã¯ã·ã§ã³ããŒã«ã®åæåãªã©ããã¢ããªã±ãŒã·ã§ã³å
šäœã§1床ã ãè¡ãããéãåŠçãã«äœ¿ããŸããçŽ æŽã«ãããªãif initialized { return }ã®ãããªãã©ã°ãã§ãã¯ãšMutexãçµã¿åãããŠèªåå®è£
ã§ããŸãããããã¯å
žåçãªãã§ãã¯ã»ã¢ã³ãã»ã»ããã®ç«¶åãã°ïŒ2ã€ã®goroutineãåæã«if !initializedãééããŠããŸãïŒãçã¿ãããå®çªã®èœãšã穎ã§ããsync.Onceã¯ãããDo(f func())ãšãã1ã¡ãœããã®APIã«æœè±¡åããå
éšã§ã¡ã¢ãªããªã¢ïŒhappens-beforeé¢ä¿ïŒãŸã§æ£ããä¿èšŒããŠãããŸãã
sync.Pool: ãäžæçã«äœ¿ã£ãŠããäžèŠã«ãªããªããžã§ã¯ããã䜿ãåãããã®ããŒã«ãã§ããGoã®ã¬ããŒãžã³ã¬ã¯ã¿ïŒGCïŒã¯èªåã§ã¡ã¢ãªãååããŠãããŸãããã¢ãã±ãŒã·ã§ã³ïŒã¡ã¢ãªç¢ºä¿ïŒèªäœã«ã³ã¹ããããããããGCãååãã¹ããªããžã§ã¯ããå¢ããã»ã©GCã®è² è·ïŒã¹ãã£ã³æéïŒãå¢ããŸããç¹ã«HTTPãã³ãã©ã®ããã«ãåãåã®ãããã¡ãé«é »åºŠã§ç¢ºä¿ããŠã¯æšãŠããåŠçã§ã¯ãsync.Poolã§ãªããžã§ã¯ããåå©çšããããšã§ã¢ãã±ãŒã·ã§ã³åæ°ãšGCè² è·ã倧ããæžãããŸãããã ãsync.Poolã¯ãã£ãã·ã¥ã§ãã£ãŠãã£ãã·ã¥ä»¥äžã®ä¿èšŒã¯ããŸãããGCãçºçãããšããŒã«å
ã®ãªããžã§ã¯ãã¯äºåãªãç Žæ£ãããããšãããããããŒã«ã«å
¥ãããã®ãå¿
ãåãåºããããšããåæã®ã³ãŒããæžãã®ã¯èª€ãã§ãã
Goèšèªã®èšèšææ³ãšããŠãã䞊è¡åŠçã«é¢ããããããèœãšã穎ïŒåæåã®äºéå®è¡ã»äžèŠãªã¢ãã±ãŒã·ã§ã³ïŒããéçºè
ãèªåã§Mutexãçµã¿åãããŠåçºæããã®ã§ã¯ãªããæšæºã©ã€ãã©ãªã®æ£ããæ€èšŒãããããªããã£ãã«ä»»ããããšããèãæ¹ã培åºãããŠããŸããsync.Onceãsync.Poolãå
éšçã«ã¯sync.Mutexãã¢ãããã¯æäœã䜿ã£ãŠå®è£
ãããŠããŸãããå©çšè
ã¯ãã®è©³çްãæèãããæå³ãæç¢ºãª1ã€ã®ã¡ãœããåŒã³åºãïŒDoã»Getã»PutïŒã§æ£ãã䞊è¡åŠçãå®çŸã§ããŸãã
ð åé¡
以äžã®2ã€ã®æ©èœãæã€ãgo run main.goã§ãã®ãŸãŸå®è¡ã§ãã1ã€ã®Goããã°ã©ã ãå®è£
ããŠãã ããã
Configãšããæ§é äœïŒãã£ãŒã«ãã¯èªç±ãäŸ:APIKey stringãLoadedAt time.Timeãªã©ïŒããã¢ããªã±ãŒã·ã§ã³å šäœã§1床ã ãçæããGetConfig() *Configãšãã颿°ãå®è£ ããŠãã ããGetConfig()ã¯äœåºŠåŒã°ããŠãããŸãè€æ°ã®goroutineããåæã«åŒã°ããŠããå éšã®åæååŠçïŒConfigãçæããåŠçïŒã¯æ£ç¢ºã«1åã ãå®è¡ãããåžžã«åã*Configã€ã³ã¹ã¿ã³ã¹ãè¿ãããšã確èªããŠãã ãã- åæååŠçã®äžã§
fmt.Println("Config initializing...")ã®ããã«ãä»ããåæåãããããšãåãããã°ãåºãããã®ãã°ãå®è¡å šäœãéããŠ1åããåºåãããªãããšãã10å以äžã®goroutineãã䞊è¡ããŠGetConfig()ãåŒã³åºãã³ãŒãã§æ€èšŒããŠãã ãã
[]byteã®ãããã¡ïŒäŸ:make([]byte, 0, 1024)ïŒã管çããsync.PoolãçšæããŠãã ãã- ããããã¡ãååŸ â äœããã®ããŒã¿ãæžã蟌ãïŒ
bytes.Bufferã[]byteãžã®appendãªã©ïŒâ 䜿ãçµãã£ããããŒã«ã«è¿åŽããããšããäžé£ã®åŠçãè¡ã颿°ãå®è£ ããŠãã ãã - è¿åŽæã«ã¯ã次ã«ååŸãã人ãååã®ããŒã¿ãèŠãŠããŸããªãããããããã¡ã®äžèº«ã空ã®ç¶æ
ïŒé·ã0ïŒã«ãªã»ããããŠãã
Putããããšã培åºããŠãã ãã - ãã®åŠçãè€æ°goroutineãã䞊è¡ã«åŒã³åºããæ£ããåäœããïŒããŒã¿ãæ··ãããªããpanicããªãïŒããšã確èªããŠãã ãã
èŠä»¶ïŒå ±éïŒ:
go run main.goã§æ£åžžçµäºããgo run -race main.goã§data raceãæ€åºãããªãããšsync.Onceã®åæåãã°ãæ£ç¢ºã«1åã ãåºåãããããšãããã°ã©ã ã®åºåã§ç¢ºèªã§ããããš- ã³ãŒãã«ã¯
package mainã»importãçç¥ããããã®ãŸãŸå®è¡ã§ããå®å šãª1ãã¡ã€ã«ãšããŠæåºããããš
ð ãã³ãïŒæ®µéçé瀺ïŒ
ãã³ã1 â æ¹åæ§
sync.Onceã¯Do(func())ãšãã1ã€ã®ã¡ãœããã ããæã€åã§ãããåæåçšã®é¢æ°ããDoã«æž¡ã圢ã«ããã°ãå
éšã§äºéå®è¡é²æ¢ã®ããžãã¯ãèªåã§æžãå¿
èŠã¯ãããŸãããsync.Poolã¯Newãã£ãŒã«ãã«ãããŒã«ã空ã®ãšãã«æ°èŠçæãã颿°ããèšå®ããGet()/Put(x)ã®2ã¡ãœããã ãã䜿ããŸããã©ã¡ãããå
±æããã*sync.Onceã»*sync.Poolã®ã€ã³ã¹ã¿ã³ã¹ããgoroutineããŸããã§åããã®ãåç
§ããããããšãåæã§ãã
ãã³ã2 â ã¢ãããŒã
sync.Onceã¯å€åãšããŠæ§é äœã«åã蟌ãããããã±ãŒãžã¬ãã«å€æ°ãšããŠvar once sync.Onceã®ããã«å®£èšããè€æ°ã®goroutineããåãonce倿°ãåç §ãã圢ã«ããŸããonce.Do(func() { ... })ã®äžã«åæååŠçãæžããŸãConfigã®å®äœãä¿æãã倿°ïŒäŸ:var config *ConfigïŒããonceãšã»ããã§ããã±ãŒãžã¬ãã«ã«çœ®ãã®ãå žåãã¿ãŒã³ã§ãsync.Poolã¯sync.Pool{New: func() any { return make([]byte, 0, 1024) }}ã®ããã«Newãèšå®ããŠåæåããŸããGet()ã¯anyåãè¿ãã®ã§ãåã¢ãµãŒã·ã§ã³ïŒ.([]byte)ïŒãå¿ èŠã§ã- ãããã¡ã
Putããåã«buf = buf[:0]ã®ããã«ã¹ã©ã€ã¹ã®é·ãã0ã«ãªã»ããããŠããè¿åŽãããšã確ä¿ãã容éïŒcapacityïŒã¯ä¿æãããŸãŸäžèº«ã ãã¯ãªã¢ã§ããŸã
ãã³ã3 â ã³ãŒãéªšæ Œ
package main
import (
"fmt"
"sync"
)
type Config struct {
APIKey string
}
var (
once sync.Once
config *Config
)
func GetConfig() *Config {
once.Do(func() {
fmt.Println("Config initializing...")
// TODO: config ã«å€ãèšå®ãã
})
return config
}
var bufPool = sync.Pool{
New: func() any {
// TODO: æ°èŠãããã¡ãè¿ã
return nil
},
}
func processWithPooledBuffer(data string) string {
buf := bufPool.Get().([]byte)
defer func() {
// TODO: ãªã»ããããŠããPutãã
bufPool.Put(buf)
}()
// TODO: buf ã« data ãæžã蟌ãã§æååãšããŠè¿ã
return ""
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
cfg := GetConfig()
_ = cfg
}(i)
}
wg.Wait()
// TODO: sync.Pool ã®äžŠè¡åŒã³åºãæ€èšŒ
}
â æš¡ç¯è§£ç
package main
import (
"fmt"
"sync"
"time"
)
// ââ sync.Once ã«ããã·ã³ã°ã«ãã³èšå®ã®åæå ââ
type Config struct {
APIKey string
LoadedAt time.Time
}
var (
once sync.Once
config *Config
)
// GetConfig ã¯äœåºŠã»äœåã®goroutineããåæã«åŒã°ããŠãã
// å
éšã®åæååŠçãæ£ç¢ºã«1åã ãå®è¡ããŠåã *Config ãè¿ãã
func GetConfig() *Config {
once.Do(func() {
fmt.Println("Config initializing...")
// å®éã«ã¯ããã§ãã¡ã€ã«èªã¿èŸŒã¿ãç°å¢å€æ°ã®è§£æãªã©ã®éãåŠçãè¡ãæ³å®ã
config = &Config{
APIKey: "dummy-api-key",
LoadedAt: time.Now(),
}
})
return config
}
// ââ sync.Pool ã«ãããããã¡ã®åå©çš ââ
var bufPool = sync.Pool{
New: func() any {
// ããŒã«ã空ã®ãšãã ãæ°èŠã«ç¢ºä¿ãããã
return make([]byte, 0, 1024)
},
}
// processWithPooledBuffer ã¯ããŒã«ãããããã¡ãåããdataãæžã蟌ãã§
// æåååããçµæãè¿ãã䜿ãçµãã£ããããã¡ã¯äžèº«ãã¯ãªã¢ããŠããè¿åŽããã
func processWithPooledBuffer(data string) string {
buf := bufPool.Get().([]byte)
defer func() {
buf = buf[:0] // é·ãã ã0ã«ãªã»ããããç¢ºä¿æžã¿ã®å®¹éã¯ä¿æãããŸãŸè¿åŽãã
bufPool.Put(buf)
}()
buf = append(buf, "processed: "...)
buf = append(buf, data...)
return string(buf)
}
func main() {
// --- èŠä»¶1ã®æ€èšŒ: sync.Once ã¯è€æ°goroutineããã§ã1åã ãå®è¡ããã ---
var wg sync.WaitGroup
results := make([]*Config, 10)
for i := 0; i < 10; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
results[n] = GetConfig()
}(i)
}
wg.Wait()
// å
šgoroutineãåã *Config ã€ã³ã¹ã¿ã³ã¹ïŒåããã€ã³ã¿ïŒãåãåã£ãŠããã確èªããã
first := results[0]
allSame := true
for _, c := range results {
if c != first {
allSame = false
}
}
fmt.Println("å
šgoroutineãåäžã€ã³ã¹ã¿ã³ã¹ãååŸ:", allSame)
// --- èŠä»¶2ã®æ€èšŒ: sync.Pool ã䜿ã£ã䞊è¡åŠçã§ããŒã¿ãæ··ãããªãã確èªãã ---
var wg2 sync.WaitGroup
outputs := make([]string, 20)
for i := 0; i < 20; i++ {
wg2.Add(1)
go func(n int) {
defer wg2.Done()
outputs[n] = processWithPooledBuffer(fmt.Sprintf("item-%d", n))
}(i)
}
wg2.Wait()
// ããããã®åºåã察å¿ãã item-n ãæ£ããå«ãã§ããã確èªããïŒããŒã¿æ··å
¥ããªããïŒã
ok := true
for i, out := range outputs {
expected := fmt.Sprintf("processed: item-%d", i)
if out != expected {
ok = false
fmt.Printf("äžäžèŽ: got=%q want=%q\n", out, expected)
}
}
fmt.Println("å
šgoroutineã®åºåãæåŸ
éã:", ok)
}
â¶ å®è¡çµæãèŠãïŒgo run main.go / go run -race main.go ãã¹ãŠæ€èšŒæžã¿ïŒ
Config initializing...
å
šgoroutineãåäžã€ã³ã¹ã¿ã³ã¹ãååŸ: true
å
šgoroutineã®åºåãæåŸ
éã: true
â» Config initializing...ãå¿
ã1åã ãåºåãããããšïŒ10åã®goroutineããåæã«GetConfig()ãåŒãã§ãè€æ°ååºåãããªãããšïŒãsync.Onceã®å¹æã§ããgo run -race main.goã§ãdata raceæ€åºãªããç¢ºèªæžã¿ã§ãã
ðª Step-by-Step 解説
var (
once sync.Once
config *Config
)
func GetConfig() *Config {
once.Do(func() {
fmt.Println("Config initializing...")
config = &Config{APIKey: "dummy-api-key", LoadedAt: time.Now()}
})
return config
}
sync.Onceã®ãŒãå€ã¯ãã®ãŸãŸãæªå®è¡ãã®ç¶æ
ãšããŠäœ¿ãããããvar once sync.Onceãšå®£èšããã ãã§åæåäžèŠã§ããonce.Do(f)ã¯ããããŸã§ã«äžåºŠãDoãæåè£ã«å®äºããŠããªããã°fãå®è¡ããããã§ãªããã°äœãããªãããšããåäœããå
éšã§ã¢ãããã¯æäœãšMutexãçµã¿åãããŠå®è£
ããŠããŸããéèŠãªã®ã¯ãè€æ°ã®goroutineãåæã«once.Do(f)ãåŒãã§ããfã®å®è¡ãå®å
šã«çµãããŸã§ä»ã®goroutineã¯Doã®åŒã³åºããããããã¯ãããŠåŸ
æ©ãããšããç¹ã§ããããã«ãããconfigãžã®æžã蟌ã¿ãå®äºããåã«å¥ã®goroutineãconfigãèªãã§ããŸãïŒåæåéäžã®nilãäžå®å
šãªå€ãèªãã§ããŸãïŒç«¶åç¶æ
ãæ§é çã«çºçããŸããã
var initialized bool
var config *Config
func GetConfigBad() *Config {
if !initialized { // è€æ°goroutineãåæã«ãããééããã
config = &Config{...}
initialized = true
}
return config
}
ãã®å®è£
ã«ã¯2ã€ã®åé¡ããããŸãã1ã€ç®ã¯ãinitializedã®ãã§ãã¯ãšæžã蟌ã¿ãã¢ãããã¯ã§ãªãããã2ã€ã®goroutineãåæã«if !initializedãééããåæååŠçã2åå®è¡ãããå¯èœæ§ãããããšã§ãïŒMutexãªãã§ã¯-raceã確å®ã«æ€åºããŸãïŒã2ã€ç®ã¯ãããšãMutexã§if !initializedã®ãããã¯ãå²ãã§ããã¡ã¢ãªã®å¯èŠæ§ïŒhappens-beforeé¢ä¿ïŒãæ£ããä¿èšŒããã®ã¯ç°¡åã§ã¯ãªãããšã§ããsync.Onceã¯ãããã®åé¡ããã¹ãŠè§£æ±ºæžã¿ã®åœ¢ã§æäŸããŠãããããããåæåã1åã ãè¡ãããããšããå Žé¢ã§ã¯èªåå®è£
ãããåžžã«sync.Onceã䜿ãã¹ãã§ãã
var bufPool = sync.Pool{
New: func() any {
return make([]byte, 0, 1024)
},
}
func processWithPooledBuffer(data string) string {
buf := bufPool.Get().([]byte)
defer func() {
buf = buf[:0]
bufPool.Put(buf)
}()
buf = append(buf, "processed: "...)
buf = append(buf, data...)
return string(buf)
}
bufPool.Get()ã¯ãããŒã«å
ã«åå©çšå¯èœãªãªããžã§ã¯ããããã°ãããè¿ãããªããã°Newãã£ãŒã«ãã®é¢æ°ãåŒãã§æ°èŠã«çæããŸããæ»ãå€ã¯anyåãªã®ã§ã.([]byte)ã§åã¢ãµãŒã·ã§ã³ããŠå
·äœçãªåã«æ»ãå¿
èŠããããŸãã䜿ãçµãã£ããPut(x)ã§ããŒã«ã«è¿åŽããŸãããè¿åŽåã«å¿
ãäžèº«ããªã»ããããã®ãéèŠã§ããbuf = buf[:0]ã¯ã¹ã©ã€ã¹ã®é·ãã ãã0ã«ããç¢ºä¿æžã¿ã®å®¹éïŒcapacityããã®äŸã§ã¯æäœ1024ãã€ãïŒã¯ä¿æãããŸãŸã«ãããããæ¬¡ã«Get()ãã人ãappendããéã«åã¢ãã±ãŒã·ã§ã³ãèµ·ãã«ãããªããŸãïŒãããsync.Poolã®ããã©ãŒãã³ã¹äžã®ã¡ãªããã®æ žå¿ã§ãïŒããããªã»ãããå¿ãããšã次ã«Get()ãã人ãååã®ããŒã¿ãbuf[:len(buf)]ã®ç¯å²ã«èŠã€ããŠããŸãå¯èœæ§ããããæå³ããªãããŒã¿æŒæŽ©ãã°ã«ã€ãªãããŸãã
for i := 0; i < 20; i++ {
wg2.Add(1)
go func(n int) {
defer wg2.Done()
outputs[n] = processWithPooledBuffer(fmt.Sprintf("item-%d", n))
}(i)
}
20åã®goroutineãåæã«processWithPooledBufferãåŒã³åºããŠããsync.Poolèªäœãgoroutineã»ãŒãã«èšèšãããŠããããïŒå
éšã§CPUã³ã¢ããšã®ããŒã«ã«ããŒã«ã䜿ããªã©ãããã¯ã®ç«¶åãæžãã工倫ããããŠããŸãïŒãågoroutineã¯èªåå°çšã®ïŒãããã¯äžæçã«åããïŒãããã¡ã«å¯ŸããŠã®ã¿appendããããšã«ãªããä»ã®goroutineã®ããŒã¿ãšæ··ããããšã¯ãããŸããããã¹ãã§ååºåãæåŸ
éãitem-nãå«ãã§ããããšã確èªããããšã§ããã®å®å
šæ§ãå®éã«æ€èšŒããŠããŸãã
ð¡ èšèšææ³ã»ãªãããæžãã®ã
sync.Onceãšsync.Poolã¯ã©ã¡ãããããããã䞊è¡åŠçã®èŠæ±ãã¿ãŒã³ããéçºè
ãæ¯åMutexããåçºæããã®ã§ã¯ãªããæå³ãäžç®ã§åããå°çšAPIãšããŠæšæºã©ã€ãã©ãªã«çšæããããšããGoã®èšèšå²åŠãäœçŸããŠããŸããonce.Do(f)ãšãã1è¡ãèŠãã°ãèªã¿æã¯å³åº§ã«ãããã¯1åããå®è¡ãããªãåæååŠçã ããšçè§£ã§ããŸããããåãããšãMutexãšbool倿°ã®çµã¿åããã§æžããŠããããèªã¿æã¯ããžãã¯ã1è¡ãã€è¿œã£ãŠãããã¯äºéå®è¡é²æ¢ã®ããã®ã³ãŒãã ããšæšæž¬ããªããã°ãªããŸãããsync.Poolã®ãããªãæç€ºçãªåå©çšãã®ææ®µãçšæãããŠããŸããããã¯ãæ®æ®µã¯æèããªããŠããããå¿
èŠãªå Žé¢ã§ã¯å¶åŸ¡ã§ããããšããGoã®ãã©ã³ã¹æèŠã®äžäŸã§ããð ä»èšèªãšã®æ¯èŒ
| èŠ³ç¹ | Go | Java | Python | Rust |
|---|---|---|---|---|
| 1åéãã®åæå | sync.Onceã®Do(f)ã§æç€ºçã«è¡šçŸã1ã¡ãœããAPIã§æå³ãæç¢º | staticåæåãããã¯ãEnumã·ã³ã°ã«ãã³ãã¿ãŒã³ã§å®çŸãã¯ã©ã¹ããŒãæã®ä¿èšŒã«äŸå | ã¢ãžã¥ãŒã«ã¬ãã«ã®å€æ°ã¯ã€ã³ããŒãæã«1åã ãè©äŸ¡ãããïŒGILã®åœ±é¿ãããåçŽïŒ | std::sync::Onceãåçã®APIãæäŸãOnceCell/LazyLockã§ããé«ã¬ãã«ãªé
å»¶åæåãå¯èœ |
| ãªããžã§ã¯ãã®åå©çšããŒã« | sync.PoolãGCãšé£åããGCçºçæã«äžèº«ãç Žæ£ããããããããŸã§ãã£ãã·ã¥ããšããèšèš | ObjectPoolã¯ãµãŒãããŒãã£å®è£
ïŒApache Commons PoolçïŒãäž»æµãæšæºã§ã¯æäŸãããªã | æšæºã§ã¯æäŸãããªããmultiprocessing.Poolã¯ããã»ã¹ããŒã«ã§å¥æŠå¿µ | æšæºã§ã¯æäŸãããªããobject-poolçã®ã¯ã¬ãŒãã«äŸåããããæææš©ã·ã¹ãã ã§åå©çšãã¿ãŒã³ãèªåèšèšãã |
| ããŒã«ããããªããžã§ã¯ãã®ä¿èšŒç¯å² | ãå ¥ãããã®ãå¿ ãåãåºãããä¿èšŒã¯ãªãïŒGCã¿ã€ãã³ã°æ¬¡ç¬¬ã§ç Žæ£ãããïŒ | ãµãŒãããŒãã£å®è£ 次第ã ããå€ãã¯æç€ºçãªç Žæ£ãŸã§ä¿æããã | 該åœãªã | ã¯ã¬ãŒã次第 |
sync.PoolããGCãšé£åããŠåæã«ç©ºã«ãªãããšãããããšããèšèšã¯ãä»èšèªã®ãªããžã§ã¯ãããŒã«ïŒå€ãã¯æç€ºçã«ç Žæ£ããªãéãä¿æããç¶ããïŒãšæ¯ã¹ããšç¬ç¹ã§ããããã¯ãã¡ã¢ãªãªãŒã¯ãé²ãããšããåå©çšã®ç¢ºå®æ§ãããåªå
ããããšããGoããããã¬ãŒããªãã®éžæã§ãã
ð å®åã§ã®äœ¿ãã©ãã
- ã·ã³ã°ã«ãã³ã®èšå®ã»æ¥ç¶ã®åæå: ããŒã¿ããŒã¹æ¥ç¶ããŒã«ãHTTPã¯ã©ã€ã¢ã³ããªã©ãã¢ããªã±ãŒã·ã§ã³å
šäœã§1ã€ã ãçæããããªãœãŒã¹ã®åæåã«
sync.Onceã䜿ãã®ã¯éåžžã«äžè¬çãªãã¿ãŒã³ã§ã - é
å»¶åæåïŒlazy initializationïŒ: èµ·åæã«å
šãŠãåæåããã®ã§ã¯ãªãããå®éã«äœ¿ãããã¿ã€ãã³ã°ã§åããŠåæåãããããšã§ã¢ããªã±ãŒã·ã§ã³ã®èµ·åæéãççž®ããçšéã«ã
sync.Onceã䜿ãããŸã - HTTPãµãŒããŒã®ã¬ã¹ãã³ã¹ãããã¡ã»JSON ãšã³ã³ãŒãçšãããã¡:
encoding/jsonã®ãããªã©ã€ãã©ãªã®å éšå®è£ ããé«ãã©ãã£ãã¯ãªHTTPãã³ãã©ã§ã®ã¬ã¹ãã³ã¹ããã£çæã«sync.Poolã䜿ããããªã¯ãšã¹ãã®ãã³ã«æ°èŠã¢ãã±ãŒã·ã§ã³ãè¡ã代ããã«ãããã¡ã䜿ãåããŸã - fmtããã±ãŒãžå
éšã®å®è£
: Goæšæºã©ã€ãã©ãªã®
fmtããã±ãŒãžãããã©ãŒãããåŠçã®å éšãããã¡ã«sync.Poolãå©çšããŠãããé«é »åºŠãªfmt.SprintfåŒã³åºãã§ãã¢ãã±ãŒã·ã§ã³ãæããããããèšèšãããŠããŸã
â ïž ãããã誀解ã»ãã¹
| 誀解ã»ãã¹ | ãªãèµ·ããã | æ£ããçè§£ |
|---|---|---|
| sync.Onceã颿°ã®ããŒã«ã«å€æ°ãšããŠæ¯åvar once sync.Onceãšå®£èšããŠããŸã | ã颿°ã®äžã§äœ¿ãã®ã ããããŒã«ã«ã§ããããšããçŽæ | ããŒã«ã«å€æ°ãšããŠå®£èšãããšåŒã³åºãã®ãã³ã«æ°ããOnceãäœãããäºéå®è¡é²æ¢ã®æå³ããªããªããOnceã¯ããã±ãŒãžã¬ãã«å€æ°ããã·ã³ã°ã«ãã³ãä¿æããæ§é äœã®ãã£ãŒã«ããšããŠãåŒã³åºãå
šäœã§å
±æããã1ã€ã®ã€ã³ã¹ã¿ã³ã¹ã«ããå¿
èŠããã |
| sync.Poolããåãåºãããªããžã§ã¯ãããå 容ãã¯ãªã¢ããã«Putã§è¿åŽãã | ã䜿ãçµãã£ããè¿ãã ãã§ããããšããæã蟌㿠| ååã®äžèº«ãæ®ã£ããŸãŸè¿åŽãããšã次ã«Getãã人ãå€ãããŒã¿ãèªãã§ããŸãå±éºããããè¿åŽåã«å¿
ãå
容ããªã»ãããã |
| sync.Poolã«å ¥ãããªããžã§ã¯ãã¯æ¬¡ã«Getããã°å¿ ãåãåºãããšæã蟌ã | ãããŒã«ããã®ã ããæ¶ããªãã¯ãããšããçŽæçãªæåŸ | sync.Poolã¯GCã®ã¿ã€ãã³ã°ã§äžèº«ãç Žæ£ããããšãããããããŸã§ããã£ãã·ã¥ãã§ããæ°žç¶çãªã³ã³ããã§ã¯ãªããNewãå¿
ãèšå®ãããŠããã¹ããªã®ã¯ãã®ãã |
| once.Do(f)ã®fã®äžã§panicãããšãäºåºŠãšåæåãããªããšåéãããããããã¯éã«äœåºŠã§ãå詊è¡ããããšåéããã | Onceã®å
éšç¶æ
é·ç§»ãæ£ç¢ºã«ææ¡ããŠããªã | fã®å®è¡äžã«panicãããšããã®Onceã¯ãå®è¡æžã¿ããšããŠæ±ããããåŸç¶ã®DoåŒã³åºãã§åã³fãå®è¡ãããå¯èœæ§ãããïŒGoã®å
¬åŒããã¥ã¡ã³ãã§æèšãããŠããæåïŒãåæååŠçãpanicãããå Žåã¯ããã®æåãèžãŸããèšèšãå¿
èŠ |
ð æ¬¡ã®ã¹ããã
- çºå±:
once.Do(f)ã®fãpanicããå Žåã®æåãå®éã«æå ã§ç¢ºèªããŠã¿ãŸãããïŒfã®äžã§panic("boom")ãèµ·ãããrecoverã§æŸãã€ã€2åç®ã®DoåŒã³åºããã©ãæ¯ãèãã芳å¯ãããšãsync.Onceã®å éšç¶æ é·ç§»ãžã®çè§£ãæ·±ãŸããŸãïŒ - 次åäºå: Day 016 â context ããã±ãŒãžâ ïŒãã£ã³ã»ã«äŒæïŒïŒæŠå¿µçè§£âå®è£ åé¡ïŒãgoroutineã®éå±€ã«ãã£ã³ã»ã«ã·ã°ãã«ãäŒããä»çµã¿ãåŠã³ãŸã