đ§ Go Concurrency Day 3 â WaitGroups & Mutex (Synchronization)
đ¯ āϞāĻā§āώā§āϝ
āĻāĻ āϤā§āĻŽāĻŋ āĻļāĻŋāĻāĻŦā§ āĻā§āĻāĻžāĻŦā§ āĻāĻāĻžāϧāĻŋāĻ goroutine āĻāĻāϏāĻžāĻĨā§ āĻāϞāϞā§āĻ āĻĒā§āϰā§āĻā§āϰāĻžāĻŽ safe āĻāĻŦāĻ predictable āϰāĻžāĻāĻž āϝāĻžā§āĨ¤ āĻŽā§āϞāϤ āĻāĻŽāϰāĻž āĻļāĻŋāĻāĻŦā§:
- WaitGroup
- Mutex / RWMutex
- Race Condition
- Race Detector (
go run -race) - Channels āĻŦāύāĻžāĻŽ Mutex āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāĻŦā§ āĻāĻĒāϝā§āĻā§āϤ
āĻā§āύ synchronization āĻĻāϰāĻāĻžāϰ?
Go-āϤ⧠goroutine āĻā§āϞ⧠āĻāĻāĻ āϏāĻžāĻĨā§ āĻāϞāϤ⧠āĻĒāĻžāϰā§āĨ¤
āĻāĻŋāύā§āϤ⧠āϝāĻĻāĻŋ āϤāĻžāϰāĻž shared data āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§, āϤāĻāύ āĻā§āϞ āĻŽāĻžāύ, āĻ āϏāĻžāĻŽāĻā§āĻāϏā§āϝāĻĒā§āϰā§āĻŖ āĻ āĻŦāϏā§āĻĨāĻž, āĻ āĻĨāĻŦāĻž race condition āĻāĻāϤ⧠āĻĒāĻžāϰā§āĨ¤
1) WaitGroup āĻā§?
sync.WaitGroup āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻž āĻšā§ āĻāĻāĻžāϧāĻŋāĻ goroutine āĻļā§āώ āĻšāĻā§āĻž āĻĒāϰā§āϝāύā§āϤ main function āĻā§ āĻ
āĻĒā§āĻā§āώāĻž āĻāϰāĻžāύā§āϰ āĻāύā§āϝāĨ¤
WaitGroup āĻĻāĻŋāϝāĻŧā§ āĻāĻŽāϰāĻž āĻŦāϞāϤ⧠āĻĒāĻžāϰāĻŋ:
âāĻāĻ X āϏāĻāĻā§āϝāĻ goroutine āĻļā§āώ āύāĻž āĻšāĻāϝāĻŧāĻž āĻĒāϰā§āϝāύā§āϤ main() āĻŦāύā§āϧ āĻšāĻŦā§ āύāĻžāĨ¤â
đš āĻŽā§āϞ āϤāĻŋāύāĻāĻŋ āĻŽā§āĻĨāĻĄ
| āĻŽā§āĻĨāĻĄ | āĻāĻžāĻ |
|---|---|
Add(n) | n āĻāĻŋ goroutine āĻļā§āϰ⧠āĻšāĻŦā§ āϤāĻž WaitGroup-āĻā§ āĻāĻžāύāĻžāύ⧠|
Done() | āĻāĻāĻāĻŋ goroutine āĻāĻžāĻ āĻļā§āώ āϤāĻž WaitGroup-āĻā§ āĻāĻžāύāĻžāύ⧠|
Wait() | āϏāĻŦ Done() āύāĻž āĻšāĻāϝāĻŧāĻž āĻĒāϰā§āϝāύā§āϤ main() āĻ āĻĒā§āĻā§āώāĻž āĻāϰ⧠|
đ¸ āĻāĻĻāĻžāĻšāϰāĻŖ: ā§ĢāĻāĻŋ goroutine āĻāĻžāϞāĻŋāϝāĻŧā§ WaitGroup āĻĻāĻŋāϝāĻŧā§ āĻ āĻĒā§āĻā§āώāĻž
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(5) // ā§ĢāĻāĻž goroutine āĻšāĻŦā§
for i := 1; i <= 5; i++ {
go func(id int) {
defer wg.Done()
fmt.Println("Goroutine āĻāϞāĻā§:", id)
}(i)
}
wg.Wait() // āϏāĻŦ goroutine āĻļā§āώ āύāĻž āĻšāĻāϝāĻŧāĻž āĻĒāϰā§āϝāύā§āϤ āĻ
āĻĒā§āĻā§āώāĻž
fmt.Println("āϏāĻŦ goroutine āĻļā§āώ āĻšāϝāĻŧā§āĻā§ â
")
}đ§Š āĻā§ āĻšāϞ⧠āĻāĻāĻžāύā§:
WaitGroup main function āĻā§ āĻŦā§āϞāĻ āĻāϰ⧠āϰāĻžāĻāĻā§ āϝāϤāĻā§āώāĻŖ āύāĻž āϏāĻŦ goroutine āĻļā§āώ āĻšā§āĨ¤
2) Shared Data + Mutex
Mutex-āĻāϰ āĻĒā§āϰā§āĻŖāϰā§āĻĒ āĻšāϞ⧠âMutual Exclusionâ (āĻĒāĻžāϰāϏā§āĻĒāϰāĻŋāĻ āĻŦāϰā§āĻāύ)āĨ¤
āĻāϰ āĻŽā§āϞ āϧāĻžāϰāĻŖāĻž āĻšāϞā§: āĻāĻāĻ āϏāĻŽāϝāĻŧā§ āĻļā§āϧā§āĻŽāĻžāϤā§āϰ āĻāĻāĻāĻŋ goroutine-āĻā§ āĻāĻāĻāĻŋ āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āĻĄā§āĻāĻž (shared data) āĻ
ā§āϝāĻžāĻā§āϏā§āϏ āĻŦāĻž āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāϰāĻžāϰ āĻ
āύā§āĻŽāϤāĻŋ āĻĻā§āĻāϝāĻŧāĻžāĨ¤
â ī¸ āϏāĻŽāϏā§āϝāĻž: Data Race
āϝāĻāύ āĻāĻāĻžāϧāĻŋāĻ goroutine đĨāĻāĻāĻ datađĨ āĻāĻāϝā§āĻā§ āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāϰāĻžāϰ āĻā§āώā§āĻāĻž āĻāϰā§, āϤāĻāύ data race āύāĻžāĻŽāĻ āĻāĻāĻāĻŋ āĻŽāĻžāϰāĻžāϤā§āĻŽāĻ āĻŦāĻžāĻ āϤā§āϰāĻŋ āĻšā§āĨ¤ āĻāϰ āĻĢāϞ⧠āĻĄā§āĻāĻž āύāώā§āĻ (corrupt) āĻšā§ā§ āϝā§āϤ⧠āĻĒāĻžāϰ⧠āĻŦāĻž āĻ
ā§āϝāĻžāĻĒā§āϞāĻŋāĻā§āĻļāύāĻāĻŋ āĻā§āϰā§āϝāĻžāĻļ āĻāϰāϤ⧠āĻĒāĻžāϰā§āĨ¤
đ āϏāĻŽāĻžāϧāĻžāύ: sync.Mutex
Go-āϤ⧠āĻāĻ data race āĻ ā§āĻāĻžāύā§āϰ āĻāύā§āϝ sync āĻĒā§āϝāĻžāĻā§āĻā§āϰ Mutex āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻž āĻšāϝāĻŧāĨ¤ āĻāĻāĻŋ āĻāĻāĻāĻŋ āϤāĻžāϞāĻžāϰ (lock) āĻŽāϤ⧠āĻāĻžāĻ āĻāϰā§āĨ¤
āĻāϰ āĻĻā§āĻāĻŋ āĻĒā§āϰāϧāĻžāύ āĻŽā§āĻĨāĻĄ āϰāϝāĻŧā§āĻā§:
-
Lock(): āĻĄā§āĻāĻž āĻ ā§āϝāĻžāĻā§āϏā§āϏ āĻāϰāĻžāϰ āĻāĻā§ āĻāĻ āĻŽā§āĻĨāĻĄ āĻāϞ āĻāϰāĻž āĻšā§āĨ¤- āϝāĻĻāĻŋ āϤāĻžāϞāĻžāĻāĻŋ āĻā§āϞāĻž āĻĨāĻžāĻā§, āϤāĻŦā§
goroutine-āĻāĻŋ āĻāĻāĻŋ āϞāĻ āĻāϰ⧠āĻāĻŦāĻ āĻāĻžāĻ āĻļā§āϰ⧠āĻāϰā§āĨ¤ - āϝāĻĻāĻŋ āĻ
āύā§āϝ
goroutineāĻāĻā§āĻ āϞāĻ āĻāϰ⧠āϰāĻžāĻā§, āϤāĻŦā§ āĻāĻāĻŋ āϤāĻžāϞāĻž āĻā§āϞāĻžāϰ āĻāύā§āϝ āĻ āĻĒā§āĻā§āώāĻž (block) āĻāϰā§āĨ¤
- āϝāĻĻāĻŋ āϤāĻžāϞāĻžāĻāĻŋ āĻā§āϞāĻž āĻĨāĻžāĻā§, āϤāĻŦā§
-
Unlock(): āĻĄā§āĻāĻž āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāϰāĻž āĻļā§āώ āĻšāϞ⧠āĻāĻ āĻŽā§āĻĨāĻĄ āĻāϞ āĻāϰāĻž āĻšā§āĨ¤- āĻāĻāĻŋ āϤāĻžāϞāĻžāĻāĻŋ āĻā§āϞ⧠āĻĻā§āϝāĻŧ, āϝāĻžāϤ⧠āĻ
āĻĒā§āĻā§āώāĻžāϰāϤ āĻ
āύā§āϝ
goroutine-āĻā§āϞāĻŋ āĻĄā§āĻāĻž āĻ ā§āϝāĻžāĻā§āϏā§āϏ āĻāϰāϤ⧠āĻĒāĻžāϰā§āĨ¤
- āĻāĻāĻŋ āϤāĻžāϞāĻžāĻāĻŋ āĻā§āϞ⧠āĻĻā§āϝāĻŧ, āϝāĻžāϤ⧠āĻ
āĻĒā§āĻā§āώāĻžāϰāϤ āĻ
āύā§āϝ
đ¸ āĻāĻĻāĻžāĻšāϰāĻŖ: 1000 āĻŦāĻžāϰ Counter āĻŦā§āĻĻā§āϧāĻŋ (Safe)
package main
import (
"fmt"
"sync"
)
func main() {
var counter = 0
var mu sync.Mutex
var wg sync.WaitGroup
wg.Add(1000)
for i := 0; i < 1000; i++ {
go func() {
defer wg.Done()
mu.Lock()
counter++ // āĻāĻāύ āύāĻŋāϰāĻžāĻĒāĻĻ
mu.Unlock()
}()
}
wg.Wait()
fmt.Println("Final Counter:", counter)
}đ āĻāĻāĻžāύ⧠Mutex counter-āĻā§ āĻāĻāϏāĻžāĻĨā§ āĻāĻ goroutine āĻĻā§āĻŦāĻžāϰāĻž āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āύāĻŋāĻļā§āĻāĻŋāϤ āĻāϰāĻā§āĨ¤
3) Mutex āĻŦāĻžāĻĻ āĻĻāĻŋāϞ⧠āĻā§ āĻšāϝāĻŧ? (Race Condition!)
package main
import (
"fmt"
"sync"
)
func main() {
var counter = 0
var wg sync.WaitGroup
wg.Add(1000)
for i := 0; i < 1000; i++ {
go func() {
defer wg.Done()
counter++ // â āĻŦāĻŋāĻĒāĻĻ! āĻāĻāĻžāϧāĻŋāĻ goroutine āĻāĻāϏāĻžāĻĨā§ āϞāĻŋāĻāĻā§
}()
}
wg.Wait()
fmt.Println("Final Counter:", counter)
}đĨ Output āĻĒāϰāĻŋāĻŦāϰā§āϤāύāĻļā§āϞ āĻšāĻŦā§ â āĻāĻāύāĻ 800, āĻāĻāύāĻ 950, āĻāĻāύāĻ 1000 āύāĻžāĨ¤ āĻāĻāĻžāĻ Race ConditionāĨ¤
4) Race Detector āĻŦā§āϝāĻŦāĻšāĻžāϰ
Go-āϤ⧠āĻŦāĻŋāϞā§āĻ-āĻāύ race detector āĻāĻā§āĨ¤
go run -race main.goāĻāĻāĻŋ āĻŦāϞāĻŦā§:
WARNING: DATA RACE
Read at ...
Previous write at ...āĻāϰ āĻŽāĻžāύ⧠āϤā§āĻŽāĻžāϰ āĻā§āĻĄā§ āĻāĻāĻžāϧāĻŋāĻ goroutine āĻāĻāϏāĻžāĻĨā§ data āĻ ā§āϝāĻžāĻā§āϏā§āϏ āĻāϰāĻā§āĨ¤
đ 5) RWMutex (Reader-Writer Mutex)
đ RWMutex (ReaderâWriter Mutex)
sync.RWMutex āĻšāϞ⧠āĻāĻŽāύ āĻāĻāĻāĻŋ āϞāĻ āϝāĻž readâŦī¸ āĻŦā§āĻļāĻŋ āĻ writeâŦī¸ āĻāĻŽ āĻāĻžāĻā§āϰ āĻā§āώā§āϤā§āϰ⧠āĻĒāĻžāϰāĻĢāϰāĻŽā§āϝāĻžāύā§āϏ āĻŦāĻžā§āĻžā§āĨ¤
âī¸ āĻāĻžāĻā§āϰ āύāĻŋā§āĻŽ
RWMutex āĻĻā§āĻāĻŋ āĻāϞāĻžāĻĻāĻž āϞāĻ āĻĻā§ā§:
RLock()â āĻāĻāĻžāϧāĻŋāĻ goroutine āĻāĻāϏāĻžāĻĨā§ data read āĻāϰāϤ⧠āĻĒāĻžāϰā§Lock()â āĻļā§āϧā§āĻŽāĻžāϤā§āϰ āĻāĻāĻāĻŋ goroutine data write āĻāϰāϤ⧠āĻĒāĻžāϰ⧠(āϏāĻŦ readers āĻ writers āĻŦā§āϞāĻ āĻšā§)
đ āĻāĻĻāĻžāĻšāϰāĻŖ
var (
value int
mu sync.RWMutex
)
func reader(id int, wg *sync.WaitGroup) {
defer wg.Done()
mu.RLock()
fmt.Println("Reader", id, "read:", value)
mu.RUnlock()
}
func writer(wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock()
value++
fmt.Println("Writer updated value:", value)
mu.Unlock()
}đš āĻāĻāĻžāύā§:
- āĻāĻāĻžāϧāĻŋāĻ
reader()āĻāĻāĻ āϏāĻŽā§ā§ āĻāĻžāϞāϤ⧠āĻĒāĻžāϰ⧠- āĻāĻŋāύā§āϤā§
writer()āĻāϏāϞā§, āĻ āύā§āϝ āϏāĻŦāĻžāĻ đĨ āĻĨā§āĻŽā§ āϝāĻžā§ āϝāϤāĻā§āώāĻŖ āύāĻž writer āĻāĻžāĻ āĻļā§āώ āĻāϰā§
⥠āĻā§āύ RWMutex āĻĻāϰāĻāĻžāϰ?
āϧāϰ⧠āϤā§āĻŽāĻžāϰ āĻĒā§āϰā§āĻā§āϰāĻžāĻŽ ⧝ā§Ļ% āϏāĻŽā§ āĻļā§āϧ⧠read āĻāϰā§, āĻāϰ ā§§ā§Ļ% āϏāĻŽā§ write āĻāϰā§āĨ¤
āϝāĻĻāĻŋ āϏāĻžāϧāĻžāϰāĻŖ Mutex āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§, āϤāĻžāĻšāϞ⧠āϏāĻŦ reader āĻāĻā§ āĻāĻā§ āĻāϞāĻŦā§ â āĻĒāĻžāϰāĻĢāϰāĻŽā§āϝāĻžāύā§āϏ āĻāĻŽā§ āϝāĻžāĻŦā§āĨ¤
RWMutex āĻāĻ āϏāĻŽāϏā§āϝāĻž āϏāĻŽāĻžāϧāĻžāύ āĻāϰā§:
- āĻāĻāĻžāϧāĻŋāĻ reader āĻāĻāϏāĻžāĻĨā§ read āĻāϰāϤ⧠āĻĒāĻžāϰ⧠(concurrent read)
- āĻāĻŋāύā§āϤ⧠writer āĻāϏāϞ⧠āϏāĻŦāĻžāĻ āĻŦā§āϞāĻ āĻšāĻŦā§ āϝāϤāĻā§āώāĻŖ āύāĻž writer āĻāĻžāĻ āĻļā§āώ āĻāϰā§
âī¸ Mutex āĻŦāύāĻžāĻŽ RWMutex
| āĻĻāĻŋāĻ | Mutex | RWMutex |
|---|---|---|
| āĻāĻāĻžāϧāĻŋāĻ reader āĻāĻāϏāĻžāĻĨā§ | â āύāĻž | â āĻšā§āϝāĻžāĻ |
| āĻāĻāĻžāϧāĻŋāĻ writer āĻāĻāϏāĻžāĻĨā§ | â āύāĻž | â āύāĻž |
| Read-heavy workload āĻ performance | āϧā§āϰ | āĻĻā§āϰā§āϤ |
| āĻŦā§āϝāĻŦāĻšāĻžāϰ | Shared data āĻāĻŽ āĻĒā§āĻž āĻšā§ | Shared data āĻŦā§āĻļāĻŋ āĻĒā§āĻž āĻšā§ |
â āĻŽāύ⧠āϰāĻžāĻā§
RWMutex āϤāĻāύ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§, āϝāĻāύ read āĻ āύā§āĻ āĻŦā§āĻļāĻŋ āĻāϰ write āĻāĻŽāĨ¤ Write āĻāϞ⧠āϏāĻŦāĻžāĻ āĻ āĻĒā§āĻā§āώāĻž āĻāϰāĻŦā§; Read āĻāϞ⧠āϏāĻŦāĻžāĻ āĻāĻāϏāĻžāĻĨā§ āĻāĻžāĻ āĻāϰāĻŦā§āĨ¤
đ Channels āĻŦāύāĻžāĻŽ Mutex
| āĻĒāϰāĻŋāϏā§āĻĨāĻŋāϤāĻŋ | āĻŦā§āϝāĻŦāĻšāĻžāϰ | āĻāĻžāϰāĻŖ |
|---|---|---|
| Shared variable āϰāĻā§āώāĻž āĻāϰāϤ⧠āĻšāĻŦā§ | Mutex | āϏāĻšāĻ āĻ āĻāĻžāϰā§āϝāĻāϰ |
| Data goroutine-āĻāϰ āĻŽāϧā§āϝ⧠āĻāĻĻāĻžāύ-āĻĒā§āϰāĻĻāĻžāύ āĻāϰāϤ⧠āĻšāĻŦā§ | Channel | Ownership āϏā§āĻĒāώā§āĻ āĻ race-free |
| Pipeline āĻŦāĻž Worker-Pool āĻĄāĻŋāĻāĻžāĻāύ | Channel | Natural fit |
đ§Š āĻ āύā§āĻļā§āϞāύ
| Exercise | āĻāĻžāĻ |
|---|---|
| 1ī¸âŖ | ā§ĢāĻāĻŋ goroutine āĻāĻžāϞāĻžāĻ āĻ WaitGroup āĻĻāĻŋā§ā§ āĻļā§āώ āĻĒāϰā§āϝāύā§āϤ āĻ āĻĒā§āĻā§āώāĻž āĻāϰāĻžāĻ |
| 2ī¸âŖ | Counter 1000 āĻŦāĻžāϰ āĻŦā§āĻĻā§āϧāĻŋ āĻāϰ⧠Mutex āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠|
| 3ī¸âŖ | Mutex āϏāϰāĻžāĻ āĻ āĻĻā§āĻā§ āĻā§ āĻšā§ |
| 4ī¸âŖ | go run -race main.go āĻĻāĻŋā§ā§ race detector āĻāĻžāϞāĻžāĻ |
| 5ī¸âŖ | RWMutex āĻĻāĻŋā§ā§ āĻāĻ Writer āĻ āĻāĻāĻžāϧāĻŋāĻ Reader āĻāĻžāϞāĻžāĻ |
đ§ āϏāĻžāϰāϏāĻāĻā§āώā§āĻĒ
| āϧāĻžāϰāĻŖāĻž | āĻāĻžāĻ |
|---|---|
| WaitGroup | āĻāĻāĻžāϧāĻŋāĻ goroutine āĻļā§āώ āĻšāĻā§āĻž āĻĒāϰā§āϝāύā§āϤ āĻ āĻĒā§āĻā§āώāĻž |
| Mutex | Shared variable āĻā§ āĻāĻāϏāĻŽā§ āĻāĻ goroutine āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāϰāϤ⧠āĻĻā§ā§ |
| RWMutex | āĻāĻāĻžāϧāĻŋāĻ reader āĻāĻāĻ āϏāĻžāĻĨā§, āĻāĻŋāύā§āϤ⧠writer āĻāĻāĻž |
| Race Condition | āĻāĻāĻžāϧāĻŋāĻ goroutine āĻāĻāϏāĻžāĻĨā§ shared data āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāϰāϞ⧠āĻšā§ |
-race flag | Race Condition āĻļāύāĻžāĻā§āϤ āĻāϰāĻžāϰ āĻā§āϞ |
| Channel āĻŦāύāĻžāĻŽ Mutex | Channel data pass āĻāϰāϤā§, đĨMutex data protect āĻāϰāϤ⧠đĨ |