ð èæ¯ç¥èïŒèªãã§ããåé¡ãžïŒ
ååã®sync.WaitGroupã¯ãè€æ°ã®goroutineã®å®äºãåŸ
ã€ãããã®éå
·ã§ãããä»åã¯èŠç¹ãå€ãããŸããrunWorkersã§ã¯ågoroutineãçµæã¹ã©ã€ã¹ã®ç°ãªãindexã«ããæžã蟌ãŸãªãã£ãããæä»å¶åŸ¡ã¯äžèŠã§ããããå®åã§ã¯è€æ°ã®goroutineãåã倿°ãmapãåæã«èªã¿æžãããå Žé¢ãé »ç¹ã«çºçããŸãïŒã¢ã¯ã»ã¹ã«ãŠã³ã¿ãã€ã³ã¡ã¢ãªãã£ãã·ã¥ãèšå®å€ã®ããããªããŒããªã©ïŒããããä¿è·ããã«æžããšdata raceïŒæªå®çŸ©åäœïŒã«ãªããŸããããã§äœ¿ãã®ãsync.Mutexã§ãã
var mu sync.Mutex
var count int
mu.Lock()
count++ // äžåºŠã«1ã€ã®goroutineããå
¥ããªããã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã
mu.Unlock()
sync.MutexïŒçžäºæä»ããã¯ïŒã¯ãä»ãã®åºéãå®è¡ããŠããã®ã¯èªåã ãã ããšããä¿èšŒãäœãéå
·ã§ããã«ãŒã«ã¯åçŽã§ãã
Lock()ã§ããã¯ãç²åŸãããä»ã®goroutineãæ¢ã«ããã¯äžãªããè§£æŸããããŸã§ãããã¯ãããUnlock()ã§ããã¯ãè§£æŸãããLock()ã®çŽåŸã«defer mu.Unlock()ãšæžãã®ãå®ç³ïŒéäžã§panicããŠã確å®ã«è§£æŸãããïŒ- ããã¯ããŠããåºéïŒã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ïŒã¯ã§ããã ãçãããã®ãGoã®æµåãããã¯äžã«I/OãéãåŠçãå ¥ãããšãä»ã®goroutineãé·æéåŸ ãããŠããŸã
sync.WaitGroupãšåæ§ãsync.Mutexãã³ããŒããŠã¯ãããŸããïŒgo vetã®copylocksã§æ€åºãããïŒã倿ž¡ããããšå¥ã
ã®ããã¯ã«ãªããæä»å¶åŸ¡ãæå³ã倱ããŸãã
ãã1ã€ãèªã¿åããæžã蟌ã¿ããå§åçã«å€ãã±ãŒã¹ïŒäŸ: èšå®å€ãmainã§1åæžã蟌ã¿ã倿°ã®goroutineãé »ç¹ã«èªã¿åããã£ãã·ã¥ïŒåãã«sync.RWMutexããããŸãã
var rw sync.RWMutex
rw.RLock() // èªã¿åãããã¯ïŒä»ã®èªã¿åããšã¯åæå®è¡ã§ãã
_ = data["key"]
rw.RUnlock()
rw.Lock() // æžã蟌ã¿ããã¯ïŒä»ã®èªã¿åãã»æžã蟌ã¿ãå
šãŠãããã¯
data["key"] = "v"
rw.Unlock()
RLock/RUnlockã¯ãèªã¿åãå°çšããã¯ãã§ãè€æ°ã®goroutineãåæã«RLockãä¿æã§ããŸãïŒèªã¿åãå士ã¯ç«¶åããªãããïŒãäžæ¹Lock/Unlockã¯ãæžã蟌ã¿ããã¯ãã§ããããä¿æããŠããéã¯ä»ã®èªã¿åãã»æžã蟌ã¿ãäžåå
¥ããŸãããèªã¿åããå€ãã¯ãŒã¯ããŒãã§ã¯ãåçŽãªMutexããäžŠè¡æ§ãäžãããŸãã
ð åé¡
以äžã®èŠä»¶ãæºããã1ã€ã®å®è¡å¯èœãªGoããã°ã©ã ãå®è£ ããŠãã ããã
SafeCounteråãå®è£ ããŠãã ãããmu sync.Mutexãšcounts map[string]intããã£ãŒã«ãã«æã¡ã以äžã®ã¡ãœãããå®è£ ããŸããInc(key string): æå®ããããŒã®ã«ãŠã³ãã1å¢ããïŒLock/Unlockã§ä¿è·ããããšïŒValue(key string) int: æå®ããããŒã®çŸåšã®ã«ãŠã³ããè¿ãïŒèªã¿åããLock/Unlockã§ä¿è·ããããšãçç±ã¯ããããã誀解ã»ãã¹ãã§æ±ããŸãïŒ
Cacheåãå®è£ ããŠãã ãããmu sync.RWMutexãšdata map[string]stringããã£ãŒã«ãã«æã¡ã以äžã®ã¡ãœãããå®è£ ããŸããSet(key, value string):Lock/Unlockã§ä¿è·ããŠæžã蟌ãGet(key string) (string, bool):RLock/RUnlockã§ä¿è·ããŠèªã¿åãïŒmapã®ã«ã³ãOKã€ãã£ãªã ã§ååšç¢ºèªãè¿ãïŒ
mainã§ã¯ãSafeCounterã«å¯ŸããŠ100åã®goroutineãèµ·åãããããããåãããŒ"requests"ã1000åã€ã³ã¯ãªã¡ã³ãããŠãã ãããå šgoroutineã®å®äºãsync.WaitGroupïŒåååŠãã ãã®ïŒã§åŸ ã£ãŠãããæçµçãªã«ãŠã³ããæ£ç¢ºã«100000ã«ãªã£ãŠããããšãåºåã§ç¢ºèªããŠãã ããïŒããã¯ããªããã°å€ã倱ãããŠãã®æ°ã«ãªããªãããšããã®åé¡ã®èŠç¹ã§ãïŒmainã§ã¯ãCacheã«å¯ŸããŠ1ã€ã®æžã蟌ã¿goroutineã§10åã®ããŒãæžã蟌ãã åŸã5åã®èªã¿åãgoroutineã䞊è¡ããŠå šããŒãè€æ°åèªã¿åããã¢ãè¡ããgo run -raceã§data raceãåºãªãããšã確èªã§ããç¶æ ã«ããŠãã ãã
go run main.goããã³go run -race main.goã§ãã®ãŸãŸå®è¡ã§ãããå®å
šãª1ã€ã®ããã°ã©ã ãšããŠæåºããŠãã ããã
ð ãã³ãïŒæ®µéçé瀺ïŒ
ãã³ã1 â æ¹åæ§
sync.Mutexã¯ãä»ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã«å
¥ã£ãŠããã®ã¯èªåã ãããšããæä»æ§ãä¿èšŒããã ãã®éå
·ã§ããLockããç¬éããUnlockãããŸã§ã®éã«æžãããã³ãŒãã ããä¿è·å¯Ÿè±¡ã«ãªããŸããä»åã®ãã€ã³ãã¯ãæžã蟌ã¿ã ãã§ãªãèªã¿åãïŒValueïŒãä¿è·ãå¿
èŠã ãšããç¹ã§ããGoã®mapã¯ã¹ã¬ããã»ãŒãã§ã¯ãªãããã1ã€ã®goroutineãæžã蟌ã¿äžã«å¥ã®goroutineãïŒããã¯ãªãã§ïŒèªã¿åããšãããšãè«ççã«ã¯å®å
šã«èŠããŠãGoã©ã³ã¿ã€ã ãfatal error: concurrent map read and writeãæ€åºããŠããã°ã©ã ãç°åžžçµäºãããããšããããŸãã
ãã³ã2 â ã¢ãããŒã
RWMutexã¯ãèªã¿åãã¯äœäººã§ãåæã«å
¥ããããæžã蟌ã¿ã¯1人ã ãããã€æžã蟌ã¿äžã¯èª°ãå
¥ããªãããšããå¶çŽãAPIãšããŠè¡šçŸãããã®ã§ããGetã®äžã§ã¯RLock()/RUnlock()ãSetã®äžã§ã¯Lock()/Unlock()ã䜿ãåããŸããåååæ§ãããã¯ç²åŸã®çŽåŸã«deferã§ã¢ã³ããã¯ãæžããšå®å
šã§ããæžã蟌ã¿goroutineãå
ã«sync.WaitGroupã§å®äºãããŠããèªã¿åãgoroutine矀ãèµ·åãããšããã¢ã®åºåãå®å®ããŠèªã¿ããããªããŸãïŒèŠä»¶ãæºããäžã§å¿
é ã§ã¯ãããŸãããæšå¥šããŸãïŒã
ãã³ã3 â ã³ãŒãéªšæ Œ
package main
import (
"fmt"
"sync"
)
type SafeCounter struct {
mu sync.Mutex
counts map[string]int
}
func NewSafeCounter() *SafeCounter {
return &SafeCounter{counts: make(map[string]int)}
}
func (c *SafeCounter) Inc(key string) {
// TODO: Lock/Unlockã§ä¿è·ããŠcounts[key]++
}
func (c *SafeCounter) Value(key string) int {
// TODO: Lock/Unlockã§ä¿è·ããŠcounts[key]ãè¿ã
return 0
}
type Cache struct {
mu sync.RWMutex
data map[string]string
}
func NewCache() *Cache {
return &Cache{data: make(map[string]string)}
}
func (c *Cache) Set(key, value string) {
// TODO: Lock/Unlockã§ä¿è·ããŠdata[key] = value
}
func (c *Cache) Get(key string) (string, bool) {
// TODO: RLock/RUnlockã§ä¿è·ããŠdata[key]ãã«ã³ãOKã€ãã£ãªã ã§è¿ã
return "", false
}
func main() {
// ãããããSafeCounterãšCacheã®åäœç¢ºèªãæžããŠãã
fmt.Println("skeleton")
}
â æš¡ç¯è§£ç
package main
import (
"fmt"
"sync"
)
// SafeCounter ã¯è€æ°goroutineããå®å
šã«ã€ã³ã¯ãªã¡ã³ãã»åç
§ã§ããã«ãŠã³ã¿ã
type SafeCounter struct {
mu sync.Mutex
counts map[string]int
}
func NewSafeCounter() *SafeCounter {
return &SafeCounter{counts: make(map[string]int)}
}
func (c *SafeCounter) Inc(key string) {
c.mu.Lock()
defer c.mu.Unlock()
c.counts[key]++
}
func (c *SafeCounter) Value(key string) int {
c.mu.Lock()
defer c.mu.Unlock()
return c.counts[key]
}
// Cache ã¯èªã¿åããå€ãã¯ãŒã¯ããŒãåãã« RWMutex ã§ä¿è·ããããã£ãã·ã¥ã
type Cache struct {
mu sync.RWMutex
data map[string]string
}
func NewCache() *Cache {
return &Cache{data: make(map[string]string)}
}
func (c *Cache) Set(key, value string) {
c.mu.Lock()
defer c.mu.Unlock()
c.data[key] = value
}
func (c *Cache) Get(key string) (string, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
v, ok := c.data[key]
return v, ok
}
func main() {
fmt.Println("=== SafeCounter: 100 goroutine x 1000åã€ã³ã¯ãªã¡ã³ã ===")
counter := NewSafeCounter()
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 1000; j++ {
counter.Inc("requests")
}
}()
}
wg.Wait()
fmt.Println(" requests count:", counter.Value("requests"), "(æåŸ
å€: 100000)")
fmt.Println("\n=== Cache: 1 writer -> 5 readers ===")
cache := NewCache()
var writerWG sync.WaitGroup
writerWG.Add(1)
go func() {
defer writerWG.Done()
for i := 0; i < 10; i++ {
cache.Set(fmt.Sprintf("key-%d", i), fmt.Sprintf("value-%d", i))
}
}()
writerWG.Wait()
fmt.Println(" æžã蟌ã¿å®äº: 10 keys")
var readerWG sync.WaitGroup
for r := 0; r < 5; r++ {
readerWG.Add(1)
go func(readerID int) {
defer readerWG.Done()
hits := 0
for round := 0; round < 20; round++ {
for k := 0; k < 10; k++ {
if _, ok := cache.Get(fmt.Sprintf("key-%d", k)); ok {
hits++
}
}
}
fmt.Printf(" reader-%d: %dåããã\n", readerID, hits)
}(r)
}
readerWG.Wait()
v, _ := cache.Get("key-0")
fmt.Println(" æçµç¢ºèª key-0 =", v)
}
â¶ å®è¡çµæãèŠãïŒgo run main.go / go run -race main.go / go vet main.go ãã¹ãŠæ€èšŒæžã¿ïŒ
=== SafeCounter: 100 goroutine x 1000åã€ã³ã¯ãªã¡ã³ã ===
requests count: 100000 (æåŸ
å€: 100000)
=== Cache: 1 writer -> 5 readers ===
æžã蟌ã¿å®äº: 10 keys
reader-3: 200åããã
reader-4: 200åããã
reader-1: 200åããã
reader-2: 200åããã
reader-0: 200åããã
æçµç¢ºèª key-0 = value-0
â» reader-Nã®åºåé åºã¯goroutineã®ã¹ã±ãžã¥ãŒãªã³ã°ã«äŸåããããå®è¡ã®ãã³ã«å€ãããŸããrequests countãšåreaderã®200åããããšããå€èªäœã¯RWMutexãæ£ããæ©èœããŠããã°åžžã«äžèŽããŸããgo run -race main.goã§ãdata raceæ€åºãªããç¢ºèªæžã¿ã§ãã
ðª Step-by-Step 解説
c.counts[key]++ã¯äžèŠ1è¡ã®åçŽãªæäœã«èŠããŸãããå
éšçã«ã¯ãèªã¿åãâå ç®âæžã蟌ã¿ãã®3ã¹ãããã§ãã100åã®goroutineãããã¯ãªãã§ãããåæã«å®è¡ãããšãè€æ°ã®goroutineãåãå€ãå€ãèªã¿åã£ãŠããå ç®ãããããããã€ãã®å ç®ã倱ãããŸãïŒread-modify-writeã®raceïŒãmu.Lock()ããmu.Unlock()ãŸã§ã1ã€ã®goroutineã ããç¬å ããããšã§ããã®3ã¹ããããäžå¯åïŒatomicïŒã«æ¯ãèãããšãä¿èšŒããŠããŸããã ãããã100 x 1000 = 100000ãšããå€ãæ£ç¢ºã«åŸãããŸãã
Valueã¯å€ã倿Žããªãã®ã§ãä¿è·äžèŠãã«èŠãããããããŸããããå®éã«ã¯ä»ã®goroutineãæžã蟌ã¿äžãããããªãmapã«å¯ŸããŠããã¯ãªãã§ã¢ã¯ã»ã¹ãããšãGoã©ã³ã¿ã€ã ã¯fatal error: concurrent map read and writeã§å³åº§ã«ããã»ã¹ãèœãšããŸããããã¯ãééã£ãå€ãèªããŠããŸãããšããç·©ãããªäžå
·åã§ã¯ãªããæ€åºããããå®è¡ãæ¢ãŸãèŽåœçãšã©ãŒã§ããèªã¿åãã§ãã£ãŠããæžã蟌ã¿ãšåãmapã«ããã¯ãªãã§ã¢ã¯ã»ã¹ããŠã¯ãããŸããã
func (c *Cache) Get(key string) (string, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
v, ok := c.data[key]
return v, ok
}
SafeCounterãšåãçºæ³ã§Mutexã䜿ãããšãã§ããŸãããCacheã¯ãæžã蟌ã¿ã¯æåã®1åã ãããã®åŸã¯èªã¿åãã倧éã«çºçããããšããé察称ãªã¯ãŒã¯ããŒãã§ããsync.Mutexã ãšèªã¿åãå士ãçŽååãããŠããŸããŸãããsync.RWMutexã®RLockã¯è€æ°goroutineãåæã«ä¿æã§ããããã5ã€ã®readerãäºãã«ãããã¯ãåããã«äžŠè¡ããŠèªã¿åããŸããSetåŽã ãLockïŒæžã蟌ã¿ããã¯ïŒã䜿ãããšã§ãæžã蟌ã¿äžã¯èª°ãèªããªãã»èªã¿åãäžã¯èª°ãæžããªãããšããæŽåæ§ãä¿ã£ãŠããŸãã
ð¡ èšèšææ³ã»ãªãããæžãã®ã
MutexãšRWMutexãåããŠçšæããŠããã®ã¯ããæä»å¶åŸ¡ã®ç²åºŠãã¯ãŒã¯ããŒãã®æ§è³ªã«åãããŠéžã¹ãããã«ããããšããææ³ã®è¡šãã§ããèªã¿æžãã®æ¯çãåçããããã¯ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã極ããŠçãå Žåã¯sync.Mutexã®æ¹ãã·ã³ãã«ã§ãªãŒããŒããããå°ãããRWMutexã䜿ãå©ç¹ã¯ã»ãšãã©ãããŸãããäžæ¹ãä»åã®Cacheã®ããã«ãèªã¿åããæžã蟌ã¿ããæ¡éãã«å€ããå Žåã«ã®ã¿ãRWMutexã®RLockäžŠè¡æ§ãå¹ããŠããŸããããŸãMutexã§æžããèšæž¬ããŠããå¿
èŠãªãRWMutexã«åãæ¿ããããšããé çªãGoãããã¢ãããŒãã§ããæåããæé©åãå
åãããŠRWMutexãéžã¶ã®ã§ã¯ãªããã·ã³ãã«ããåªå
ããå¿
èŠã«ãªã£ãŠããéå
·ãæã¡æ¿ãããšããèãæ¹ã¯ãGoã®æšæºã©ã€ãã©ãªå
šäœã«äžè²«ããŠããŸããLock()ã®çŽåŸã«defer Unlock()ãæžãæ
£ç¿ã¯ãsync.WaitGroupã®defer wg.Done()ãšåãçç±ã«åºã¥ããŸããã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã®éäžã§panicãèµ·ããŠããdeferãããã°ããã¯ã¯ç¢ºå®ã«è§£æŸãããŸãããããæ ããšãããã¯ãæã£ããŸãŸpanicããgoroutineãçµäºããä»ã®å
šgoroutineãæ°žé ã«Lock()ã§ãããã¯ãç¶ãããããããã¯ã«ãªããŸããð ä»èšèªãšã®æ¯èŒ
| èŠ³ç¹ | Go | Java | Python | JavaScript/Node.js |
|---|---|---|---|---|
| åºæ¬çãªæä»ãã㯠| sync.MutexïŒLock/UnlockïŒ | synchronizedããã㯠ãŸã㯠ReentrantLock | threading.LockïŒacquire/releaseãwith lock:æšå¥šïŒ | ã·ã³ã°ã«ã¹ã¬ããã®ã€ãã³ãã«ãŒãã®ããéåžžäžèŠïŒWorker Threadséã¯SharedArrayBuffer+Atomicsãå¿ èŠãªç¹æ®ã±ãŒã¹ã®ã¿ïŒ |
| èªã¿åãåªéãã㯠| sync.RWMutexïŒRLock/RUnlock, Lock/UnlockïŒ | ReentrantReadWriteLock | threading.Lockã«RWMutexçžåœã®æšæºåã¯ãªãããµãŒãããŒãã£ïŒreaderwriterlockçïŒãå¿
èŠ | 該åœãªã |
| åå ¥å¯èœæ§ | äžå¯ïŒåãgoroutineã2åLockãããšãããããã¯ïŒ | synchronized/ReentrantLockã¯åå
¥å¯èœïŒåäžã¹ã¬ãããªãå€éããã¯å¯ïŒ | Lockã¯éåå
¥ã»RLockã¯åå
¥å¯èœãªå¥ã¯ã©ã¹ãšããŠæäŸ | 該åœãªã |
| ããã¯è§£æŸå¿ã察ç | defer mu.Unlock()ãLockçŽåŸã«æžãèŠçŽïŒèšèªæ©èœã§ã¯ãªãæ
£ç¿ïŒ | try { synchronized } finally { }ããŸãã¯try-with-resourcesçãã¿ãŒã³ | with lock:ã³ã³ããã¹ããããŒãžã£ã§èªåè§£æŸ | 該åœãªã |
Goã®sync.Mutexãéåå
¥å¯èœïŒnon-reentrantïŒã§ããç¹ã¯Javaã®synchronizedãšå€§ããç°ãªããŸããJavaã§ã¯åãã¹ã¬ãããååž°çã«åãããã¯ãååŸããŠãåé¡ãããŸããããGoã§åãgoroutineãä¿æäžã®ããã¯ãããäžåºŠLock()ããããšãããšãèªåèªèº«ã®è§£æŸãæ°žé ã«åŸ
ã€ãããããã¯ã«ãªããŸããããã¯Goããããã¯ã®ç¶æ
ãæé»çã«è¿œè·¡ããä»çµã¿ïŒã©ã®ã¹ã¬ãããæã£ãŠãããçïŒãããããŠæãããã·ã³ãã«ãªã«ãŠã³ã¿çå®è£
ã«çããŠããããã§ããåå
¥ãå¿
èŠã«ãªãèšèšèªäœãé¿ããããã¯ãåã責åã1ã€ã®é¢æ°ã«éã蟌ããããšããã®ãGoãããåé¿çã§ãã
ð å®åã§ã®äœ¿ãã©ãã
- ã€ã³ã¡ã¢ãªãã£ãã·ã¥ã»èšå®ã®ããããªããŒã:
Cacheã®ããã«ãã¢ããªèµ·åæã宿çã«æžã蟌ã¿ããªã¯ãšã¹ãåŠçäžã¯é »ç¹ã«èªã¿åããšããé察称ã¯ãŒã¯ããŒãã«RWMutexã¯æé© - ã¡ããªã¯ã¹ã»ã«ãŠã³ã¿éèš: ãªã¯ãšã¹ãæ°ã»ãšã©ãŒæ°ãªã©ããã³ãã©ãã䞊è¡ã«ã€ã³ã¯ãªã¡ã³ããã
SafeCounterãã¿ãŒã³ã¯ãç°¡æçãªèªåã¡ããªã¯ã¹å®è£ ã§ãã䜿ãããïŒæ¬çªã§ã¯Prometheusã¯ã©ã€ã¢ã³ãã©ã€ãã©ãªã®å éšå®è£ ãåæ§ã®èãæ¹ïŒ - ã³ãã¯ã·ã§ã³ããŒã«ã»ã¬ãžã¹ããªã®ç¶æ 管ç: çŸåšäœ¿çšäžã®ãªãœãŒã¹äžèЧãªã©ãmapã§ç®¡çããè€æ°goroutineããç»é²ã»è§£é€ã»åç §ãçºçããå Žé¢
- ã°ã¬ãŒã¹ãã«ã·ã£ããããŠã³äžã®ãã©ã°ç®¡ç: ãã·ã£ããããŠã³äžãã©ãããã®ãããªãã©ã°ãè€æ°goroutineããèªã¿æžãããå ŽåïŒãã ãåçŽãªbool 1ã€ãªã次ã
ååŠã¶
sync/atomicã®æ¹ãé©ããŠããããšãå€ãïŒ
â ïž ãããã誀解ã»ãã¹
| 誀解ã»ãã¹ | ãªãèµ·ããã | æ£ããçè§£ |
|---|---|---|
| èªã¿åãã¡ãœããã¯ããã¯äžèŠã ãšæã蟌ã | ãå€ã倿Žããªããªãå®å šããšããçŽæã§æžããŠããŸã | ä»ã®goroutineãæžã蟌ã¿äžã®å¯èœæ§ããã以äžãèªã¿åããå¿
ãä¿è·ãããmapãžã®ç¡ä¿è·ãªäžŠè¡ã¢ã¯ã»ã¹ã¯fatal error: concurrent map read and writeã§ããã»ã¹ãèœã¡ã |
| RWMutexãåžžã«Mutexããéããšæã蟌ã | ãèªã¿åãå°çšããã¯ãããããåžžã«æå©ããšããååããã®èª€è§£ | æžã蟌ã¿ãå€ãããŸãã¯ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã極ããŠçãã¯ãŒã¯ããŒãã§ã¯RWMutexã®ç®¡çãªãŒããŒããããMutexããé
ããªãããšããããèšæž¬ããã«éžã°ãªã |
| åãgoroutineå ã§Lock()ã2ååŒãã§ããŸãïŒååž°çãªã¡ãœããåŒã³åºããªã©ïŒ | Javaã®synchronizedã®åå ¥å¯èœãªæèŠãæã¡èŸŒãã§ããŸã | Goã®sync.Mutexã¯éåå
¥å¯èœã2åç®ã®Lock()ã¯èªåèªèº«ã®Unlock()ãåŸ
ã¡ç¶ãããããããã¯ã«ãªã |
| RLockäžã«LockãåŒãã§ããŸãïŒèªã¿åãããã¯ä¿æäžã«åãgoroutineã§æžã蟌ã¿ããã¯ãåãããšããïŒ | ãèªãã§ãããã®å Žã§æŽæ°ãããããšããèªç¶ãªçºæ³ | RLockãä¿æãããŸãŸLockã¯ååŸã§ãããããããã¯ã«ãªããèªã¿åãâå€æâæžã蟌ã¿ãå¿
èŠãªå Žåã¯ããã£ããRUnlockããŠããæ¹ããŠLockãåãçŽãèšèšã«ãã |
| sync.Mutexãsync.RWMutexãå€ãšããŠæ§é äœããšã³ããŒããŠããŸã | æ§é äœã颿°ã®åŒæ°ãæ»ãå€ãšããŠå€æž¡ãããçµæãæå³ããããã¯ãã³ããŒããã | WaitGroupãšåæ§ã³ããŒçŠæ¢ãæ§é äœã¯ãã€ã³ã¿ïŒ*SafeCounterïŒã§åãæž¡ããgo vetã®copylocksãæ€åºããŠããã |
ð æ¬¡ã®ã¹ããã
- çºå±:
SafeCounter.Incããããã¯ã䜿ããã«sync/atomicããã±ãŒãžã®atomic.Int64ã§æžãæããŠã¿ãŸããããåçŽãªæ°å€ã®ã€ã³ã¯ãªã¡ã³ãã ããªãMutexãã軜éã«å®è£ ã§ããããšãäœæããŠãã ããïŒCacheã®ãããªè€åçãªç¶æ ã«ã¯atomicã¯äœ¿ãããMutex/RWMutexãå¿ èŠã§ããããšãåãããŠç¢ºèªããŸãããïŒ - 次åäºå: Day 014 â sync.Once, sync.PoolïŒå®è£ åé¡ïŒãåæåãäžåºŠã ãå®è¡ããä»çµã¿ãšããªããžã§ã¯ãã®åå©çšã«ããGCè² è·è»œæžãåŠã³ãŸã