Go Concurrency Starter Pack
κ°μ
μ§§μ μκ°
κ³ μΈμ΄μλ λ§μ λμμ± κ΄λ¦¬λ₯Ό μν λκ΅¬κ° μμ΅λλ€. μ΄ μν°ν΄μμλ κ·Έ μ€ μΌλΆμ νΈλ¦λ€μ μκ°ν΄λ리λλ‘ νκ² μ΅λλ€.
κ³ λ£¨ν΄?
goroutineμ κ³ μΈμ΄μμ μ§μνλ μλ‘μ΄ νμμ λμμ± λͺ¨λΈμ λλ€. μΌλ°μ μΌλ‘ νλ‘κ·Έλ¨μ λμμ μ¬λ¬ μμ μ μννκΈ° μν΄ OSμκ²μ OS μ€λ λλ₯Ό λ°μμ, μ½μ΄ μλ§νΌ λ³λ ¬μ μΌλ‘ μμ μ μνν©λλ€. κ·Έλ¦¬κ³ λ μμ λ¨μμ λμμ±μ μννκΈ° μν΄μλ μ μ λλμμ κ·Έλ¦° μ€λ λλ₯Ό μμ±νμ¬, νλμ OS μ€λ λ λ΄μμ μ¬λ¬ κ·Έλ¦° μ€λ λκ° λμκ°λ©° μμ μ μννλλ‘ ν©λλ€. νμ§λ§ κ³ λ£¨ν΄μ κ²½μ°μ μ΄λ¬ν ννμ κ·Έλ¦° μ€λ λλ₯Ό λμ± μκ³ ν¨μ¨μ μΌλ‘ λ§λ€μμ΅λλ€. μ΄λ¬ν κ³ λ£¨ν΄μ μ€λ λλ³΄λ€ λ μ μ λ©λͺ¨λ¦¬λ₯Ό μ¬μ©νλ©°, μ€λ λλ³΄λ€ λ λΉ λ₯΄κ² μμ±λκ³ κ΅μ²΄λ μ μμ΅λλ€.
κ³ λ£¨ν΄μ μ¬μ©νκΈ° μν΄μλ λ¨μν go ν€μλλ§ μ¬μ©νλ©΄ λ©λλ€. μ΄λ νλ‘κ·Έλ¨μ μμ±νλ κ³Όμ μμ μ§κ΄μ μΌλ‘ λκΈ° μ½λλ₯Ό λΉλκΈ° μ½λλ‘ μ€νν μ μλλ‘ ν©λλ€.
1package main
2
3import (
4 "fmt"
5 "time"
6)
7
8func main() {
9 ch := make(chan struct{})
10 go func() {
11 defer close(ch)
12 time.Sleep(1 * time.Second)
13 fmt.Println("Hello, World!")
14 }()
15
16 fmt.Println("Waiting for goroutine...")
17 for range ch {}
18}
μ΄ μ½λλ κ°λ¨νκ² 1μ΄ μ¬μλ€κ° Hello, World!λ₯Ό μΆλ ₯νλ λκΈ°μ μ½λλ₯Ό λΉλκΈ° νλ¦μΌλ‘ λ³κ²½ν©λλ€. μ§κΈμ μμ λ κ°λ¨νμ§λ§, μ‘°κΈ λ³΅μ‘ν μ½λλ₯Ό λκΈ° μ½λμμ λΉλκΈ° μ½λλ‘ λ³κ²½νκ² λλ©΄, μ½λμ κ°λ
μ±κ³Ό κ°μμ±, μ΄ν΄λκ° κΈ°μ‘΄μ async awaitλ promise κ°μ λ°©μλ³΄λ€ λμ± μ’μμ§λλ€.
λ€λ§ λ§μ κ²½μ°μ, μ΄λ¬ν λκΈ° μ½λλ₯Ό λ¨μν λΉλκΈ°λ‘ νΈμΆνλ νλ¦κ³Ό fork & joinκ³Ό κ°μ νλ¦(λ§μΉ λΆν μ 볡과 μ μ¬ν νλ¦)μ μ΄ν΄νμ§ λͺ»ν μνμμ μ μ’μ κ³ λ£¨ν΄ μ½λκ° λ§λ€μ΄μ§κΈ°λ ν©λλ€. μ΄λ¬ν κ²½μ°μ λλΉν μ λͺκ°μ§ λ°©λ²κ³Ό κΈ°λ²μ μ΄ μν°ν΄μμ μκ°νλλ‘ νκ² μ΅λλ€.
λμμ± κ΄λ¦¬
context
첫λ²μ§Έ κ΄λ¦¬ κΈ°λ²μΌλ‘ contextκ° λ±μ₯νλ 건 μμΈμΌ μ μμ΅λλ€. νμ§λ§ κ³ μΈμ΄μμ contextλ λ¨μν μ·¨μ κΈ°λ₯μ λμ΄μ, μ 체 μμ
νΈλ¦¬λ₯Ό κ΄λ¦¬νλ λ°μ νμν μν μ ν©λλ€. λ§μ½ λͺ¨λ₯΄μλ λΆλ€μ μν΄ κ°λ¨ν ν΄λΉ ν¨ν€μ§λ₯Ό μ€λͺ
νκ² μ΅λλ€.
1package main
2
3func main() {
4 ctx, cancel := context.WithCancel(context.Background())
5 defer cancel()
6
7 go func() {
8 <-ctx.Done()
9 fmt.Println("Context is done!")
10 }()
11
12 time.Sleep(1 * time.Second)
13
14 cancel()
15
16 time.Sleep(1 * time.Second)
17}
μ μ½λλ contextλ₯Ό μ¬μ©νμ¬, 1μ΄ νμ Context is done!λ₯Ό μΆλ ₯νλ μ½λμ
λλ€. contextλ Done() λ©μλλ₯Ό ν΅ν΄ μ·¨μ μ¬λΆλ₯Ό νμΈν μ μμΌλ©°, WithCancel, WithTimeout, WithDeadline, WithValue λ±μ λ©μλλ₯Ό ν΅ν΄ λ€μν μ·¨μ λ°©λ²μ μ 곡ν©λλ€.
κ°λ¨ν μμλ₯Ό λ§λ€μ΄ λ³΄κ² μ΅λλ€. λ§μ½ μ¬λ¬λΆλ€μ΄ μ΄λ€ λ°μ΄ν°λ₯Ό κ°μ Έμ€κΈ° μν΄ aggregator ν¨ν΄μ μ¬μ©νμ¬, user, post, commentλ₯Ό κ°μ Έμ€λ μ½λλ₯Ό μμ±νλ€κ³ κ°μ ν΄λ΄
μλ€. κ·Έλ¦¬κ³ λͺ¨λ μμ²μ΄ 2μ΄ λ΄μ μ΄λ£¨μ΄μ ΈμΌνλ€λ©΄, λ€μκ³Ό κ°μ΄ μμ±ν μ μμ΅λλ€.
1package main
2
3func main() {
4 ctx, cancel := context.WithTimeout(context.Background(), 2 * time.Second)
5 defer cancel()
6
7 ch := make(chan struct{})
8 go func() {
9 defer close(ch)
10 user := getUser(ctx)
11 post := getPost(ctx)
12 comment := getComment(ctx)
13
14 fmt.Println(user, post, comment)
15 }()
16
17 select {
18 case <-ctx.Done():
19 fmt.Println("Timeout!")
20 case <-ch:
21 fmt.Println("All data is fetched!")
22 }
23}
μ μ½λλ 2μ΄ λ΄μ λͺ¨λ λ°μ΄ν°λ₯Ό κ°μ Έμ€μ§ λͺ»νλ©΄ Timeout!μ μΆλ ₯νκ³ , λͺ¨λ λ°μ΄ν°λ₯Ό κ°μ Έμ€λ©΄ All data is fetched!λ₯Ό μΆλ ₯ν©λλ€. μ΄λ¬ν λ°©μμΌλ‘ contextλ₯Ό μ¬μ©νλ©΄, μ¬λ¬ κ³ λ£¨ν΄μ΄ λμνλ μ½λμμλ μ·¨μμ νμμμμ μ½κ² κ΄λ¦¬ν μ μμ΅λλ€.
μ΄μ κ΄λ ¨λ λ€μν context κ΄λ ¨ ν¨μμ λ©μλκ° godoc contextμμ νμΈ κ°λ₯ν©λλ€. κ°λ¨ν κ²μ νμ΅νμ¬ νΈν μ΄μ©ν μ μκ² λμ ¨μΌλ©΄ ν©λλ€.
channel
unbuffered channel
channelμ κ³ λ£¨ν΄ κ°μ ν΅μ μ μν λꡬμ
λλ€. channelμ make(chan T)λ‘ μμ±ν μ μμ΅λλ€. μ΄λ, Tλ ν΄λΉ channelμ΄ μ λ¬ν λ°μ΄ν°μ νμ
μ
λλ€. channelμ <-λ‘ λ°μ΄ν°λ₯Ό μ£Όκ³ λ°μ μ μμΌλ©°, closeλ‘ channelμ λ«μ μ μμ΅λλ€.
1package main
2
3func main() {
4 ch := make(chan int)
5 go func() {
6 ch <- 1
7 ch <- 2
8 close(ch)
9 }()
10
11 for i := range ch {
12 fmt.Println(i)
13 }
14}
μ μ½λλ channelμ μ¬μ©νμ¬ 1κ³Ό 2λ₯Ό μΆλ ₯νλ μ½λμ
λλ€. μ΄ μ½λμμλ λ¨μνκ² channelμ κ°μ 보λ΄κ³ λ°λ κ²λ§μ 보μ¬μ£Όκ³ μμ΅λλ€. νμ§λ§ channelμ μ΄λ³΄λ€ λ λ§μ κΈ°λ₯μ μ 곡ν©λλ€. λ¨Όμ buffered channelκ³Ό unbuffered channelμ λν΄ μμλ³΄κ² μ΅λλ€. μμνκΈ°μ μμ μμ μμ±λ μμ λ unbuffered channelλ‘, μ±λμ λ°μ΄ν°λ₯Ό 보λ΄λ νλκ³Ό λ°μ΄ν°λ₯Ό λ°λ νλμ΄ λμμ μ΄λ£¨μ΄μ ΈμΌν©λλ€. λ§μ½ μ΄λ¬ν νλμ΄ λμμ μ΄λ£¨μ΄μ§μ§ μλλ€λ©΄, λ°λλ½μ΄ λ°μν μ μμ΅λλ€.
buffered channel
λ§μ½ μ μ½λκ° λ¨μ μΆλ ₯μ΄ μλλΌ λ¬΄κ±°μ΄ μμ
μ μννλ νλ‘μΈμ€ 2κ°μ§λΌλ©΄ μ΄λ€κ°μ? λλ²μ§Έ νλ‘μΈμ€κ° μ½μ΄μ μ²λ¦¬λ₯Ό μννλ€κ° μ₯κΈ°κ° νμ΄ κ±Έλ¦°λ€λ©΄, 첫λ²μ§Έ νλ‘μΈμ€λ ν΄λΉ μκ° λμ λ©μΆκ² λ κ²μ
λλ€. μ ν¬λ μ΄λ¬ν μν©μ λ°©μ§νκΈ° μν΄ buffered channelμ μ¬μ©ν μ μμ΅λλ€.
1package main
2
3func main() {
4 ch := make(chan int, 2)
5 go func() {
6 ch <- 1
7 ch <- 2
8 close(ch)
9 }()
10
11 for i := range ch {
12 fmt.Println(i)
13 }
14}
μ μ½λλ buffered channelμ μ¬μ©νμ¬ 1κ³Ό 2λ₯Ό μΆλ ₯νλ μ½λμ
λλ€. μ΄ μ½λμμλ buffered channelμ μ¬μ©νμ¬, channelμ λ°μ΄ν°λ₯Ό 보λ΄λ νλκ³Ό λ°μ΄ν°λ₯Ό λ°λ νλμ΄ λμμ μ΄λ£¨μ΄μ§μ§ μμλ λλλ‘ λ§λ€μμ΅λλ€. μ΄λ κ² μ±λμ λ²νΌλ₯Ό λκ² λλ©΄, ν΄λΉ κΈΈμ΄λ§νΌ μ¬μ κ° μ겨 νμμ μμ
μ μν₯μΌλ‘μΈν΄ λ°μνλ μμ
μ§μ°μ λ°©μ§ν μ μμ΅λλ€.
select
μ¬λ¬ μ±λμ λ€λ£° λ, select λ¬Έλ²μ μ¬μ©νλ©΄ μ½κ² fan-in ꡬ쑰λ₯Ό ꡬνν μ μμ΅λλ€.
1package main
2
3import (
4 "fmt"
5 "time"
6)
7
8func main() {
9 ch1 := make(chan int, 10)
10 ch2 := make(chan int, 10)
11 ch3 := make(chan int, 10)
12
13 go func() {
14 for {
15 ch1 <- 1
16 time.Sleep(1 * time.Second)
17 }
18 }()
19 go func() {
20 for {
21 ch2 <- 2
22 time.Sleep(2 * time.Second)
23 }
24 }()
25 go func() {
26 for {
27 ch3 <- 3
28 time.Sleep(3 * time.Second)
29 }
30 }()
31
32 for i := 0; i < 3; i++ {
33 select {
34 case v := <-ch1:
35 fmt.Println(v)
36 case v := <-ch2:
37 fmt.Println(v)
38 case v := <-ch3:
39 fmt.Println(v)
40 }
41 }
42}
μ μ½λλ μ£ΌκΈ°μ μΌλ‘ 1, 2, 3μ μ λ¬νλ 3κ°μ μ±λμ λ§λ€κ³ , selectλ₯Ό μ¬μ©νμ¬ μ±λμμ κ°μ λ°μ μΆλ ₯νλ μ½λμ
λλ€. μ΄λ¬ν λ°©μμΌλ‘ selectλ₯Ό μ¬μ©νλ©΄, μ¬λ¬ μ±λμμ λμμ λ°μ΄ν°λ₯Ό μ λ¬ λ°μΌλ©΄μ, μ±λμμ κ°μ λ°λ λλ‘ μ²λ¦¬ν μ μμ΅λλ€.
for range
channelμ for rangeλ₯Ό μ¬μ©νμ¬ μ½κ² λ°μ΄ν°λ₯Ό λ°μ μ μμ΅λλ€. for rangeλ₯Ό μ±λμ μ¬μ©νκ² λλ©΄ ν΄λΉ μ±λμ λ°μ΄ν°κ° μΆκ°λ λλ§λ€ λμνκ² λλ©°, μ±λμ΄ λ«νλ©΄ 루νλ₯Ό μ’
λ£ν©λλ€.
1package main
2
3func main() {
4 ch := make(chan int)
5 go func() {
6 ch <- 1
7 ch <- 2
8 close(ch)
9 }()
10
11 for i := range ch {
12 fmt.Println(i)
13 }
14}
μ μ½λλ channelμ μ¬μ©νμ¬ 1κ³Ό 2λ₯Ό μΆλ ₯νλ μ½λμ
λλ€. μ΄ μ½λμμλ for rangeλ₯Ό μ¬μ©νμ¬ μ±λμ λ°μ΄ν°κ° μΆκ°λ λλ§λ€ λ°μ΄ν°λ₯Ό λ°μ μΆλ ₯ν©λλ€. κ·Έλ¦¬κ³ μ±λμ΄ λ«νλ©΄ 루νλ₯Ό μ’
λ£ν©λλ€.
μμ λͺλ² μμ±ν λλ‘ μ΄ λ¬Έλ²μ λ¨μ λκΈ°ν μλ¨μ μ¬μ©ν μλ μμ΅λλ€.
1package main
2
3func main() {
4 ch := make(chan struct{})
5 go func() {
6 defer close(ch)
7 time.Sleep(1 * time.Second)
8 fmt.Println("Hello, World!")
9 }()
10
11 fmt.Println("Waiting for goroutine...")
12 for range ch {}
13}
μ μ½λλ 1μ΄ μ¬μλ€κ° Hello, World!λ₯Ό μΆλ ₯νλ μ½λμ
λλ€. μ΄ μ½λμμλ channelμ μ¬μ©νμ¬ λκΈ°μ μ½λλ₯Ό λΉλκΈ°μ μ½λλ‘ λ³κ²½νμμ΅λλ€. μ΄λ¬ν λ°©μμΌλ‘ channelμ μ¬μ©νλ©΄, λκΈ°μ μ½λλ₯Ό λΉλκΈ°μ μ½λλ‘ μ½κ² λ³κ²½νκ³ , join μ§μ μ μ€μ ν μ μμ΅λλ€.
etc
- nil channelμ λ°μ΄ν°λ₯Ό 보λ΄κ±°λ λ°μΌλ©΄, 무ν 루νμ λΉ μ Έ λ°λλ½μ΄ λ°μν μ μμ΅λλ€.
- μ±λμ λ«μ νμ λ°μ΄ν°λ₯Ό 보λ΄λ©΄, panicμ΄ λ°μν©λλ€.
- μ±λμ κ΅³μ΄ λ«μ§ μμλ, GCκ° μκ±°νλ©΄μ μ±λμ λ«μ΅λλ€.
mutex
spinlock
spinlockμ λ°λ³΅λ¬Έμ λλ©° κ³μν΄μ λ½μ μλνλ λκΈ°ν λ°©λ²μ
λλ€. κ³ μΈμ΄μμ ν¬μΈν°λ₯Ό μ¬μ©νμ¬ μ½κ² μ€νλ½μ ꡬνν΄λ³Ό μ μμ΅λλ€.
1package spinlock
2
3import (
4 "runtime"
5 "sync/atomic"
6)
7
8type SpinLock struct {
9 lock uintptr
10}
11
12func (s *SpinLock) Lock() {
13 // Continua a provare a ottenere il lock finchΓ© non ci riesce
14 for !atomic.CompareAndSwapUintptr(&s.lock, 0, 1) {
15 // Cede il controllo al scheduler per evitare lo spinning attivo
16 runtime.Gosched()
17 }
18}
19
20func (s *SpinLock) Unlock() {
21 // Rilascia il lock impostandolo a 0
22 atomic.StoreUintptr(&s.lock, 0)
23}
24
25func NewSpinLock() *SpinLock {
26 // Crea e restituisce una nuova istanza di SpinLock
27 return &SpinLock{}
28}
μ μ½λλ spinlock ν¨ν€μ§λ₯Ό ꡬνν μ½λμ
λλ€. μ΄ μ½λμμλ sync/atomic ν¨ν€μ§λ₯Ό μ¬μ©νμ¬ SpinLockμ ꡬννμμ΅λλ€. Lock λ©μλμμλ atomic.CompareAndSwapUintptrλ₯Ό μ¬μ©νμ¬ λ½μ μλνκ³ , Unlock λ©μλμμλ atomic.StoreUintptrλ₯Ό μ¬μ©νμ¬ λ½μ ν΄μ ν©λλ€. μ΄ λ°©μμ μ¬μ§ μκ³ λ½μ μλνκΈ° λλ¬Έμ, λ½μ μ»μ λκΉμ§ κ³μν΄μ CPUλ₯Ό μ¬μ©νκ² λμ΄, 무ν 루νμ λΉ μ§ μ μμ΅λλ€. λ°λΌμ, spinlockμ λ¨μν λκΈ°νμ μ¬μ©νκ±°λ, μ§§μ μκ° λμλ§ μ¬μ©νλ κ²½μ°μ μ¬μ©νλ κ²μ΄ μ’μ΅λλ€.
sync.Mutex
mutexλ κ³ λ£¨ν΄ κ°μ λκΈ°νλ₯Ό μν λꡬμ
λλ€. sync ν¨ν€μ§μμ μ 곡νλ mutexλ Lock, Unlock, RLock, RUnlock λ±μ λ©μλλ₯Ό μ 곡ν©λλ€. mutexλ sync.Mutexλ‘ μμ±ν μ μμΌλ©°, sync.RWMutexλ‘ μ½κΈ°/μ°κΈ° λ½μ μ¬μ©ν μλ μμ΅λλ€.
1package main
2
3import (
4 "sync"
5)
6
7func main() {
8 var mu sync.Mutex
9 var count int
10
11 go func() {
12 mu.Lock()
13 count++
14 mu.Unlock()
15 }()
16
17 mu.Lock()
18 count++
19 mu.Unlock()
20
21 println(count)
22}
μ μ½λμμλ κ±°μ λμμ λ κ³ λ£¨ν΄μ΄ λμΌν count λ³μμ μ κ·Όνκ² λ©λλ€. μ΄λ, mutexλ₯Ό μ¬μ©νμ¬ count λ³μμ μ κ·Όνλ μ½λλ₯Ό μκ³ μμμΌλ‘ λ§λ€μ΄μ£Όλ©΄, count λ³μμ λν λμ μ κ·Όμ λ§μ μ μμ΅λλ€. κ·Έλ¬λ©΄ μ΄ μ½λλ λͺλ²μ μ€ννλ λμΌνκ² 2λ₯Ό μΆλ ₯νκ² λ©λλ€.
sync.RWMutex
sync.RWMutexλ μ½κΈ° λ½κ³Ό μ°κΈ° λ½μ ꡬλΆνμ¬ μ¬μ©ν μ μλ mutexμ
λλ€. RLock, RUnlock λ©μλλ₯Ό μ¬μ©νμ¬ μ½κΈ° λ½μ κ±Έκ³ ν΄μ ν μ μμ΅λλ€.
1package cmap
2
3import (
4 "sync"
5)
6
7type ConcurrentMap[K comparable, V any] struct {
8 sync.RWMutex
9 data map[K]V
10}
11
12func (m *ConcurrentMap[K, V]) Get(key K) (V, bool) {
13 m.RLock()
14 defer m.RUnlock()
15
16 value, ok := m.data[key]
17 return value, ok
18}
19
20func (m *ConcurrentMap[K, V]) Set(key K, value V) {
21 m.Lock()
22 defer m.Unlock()
23
24 m.data[key] = value
25}
μ μ½λλ sync.RWMutexλ₯Ό μ¬μ©νμ¬ ConcurrentMapμ ꡬνν μ½λμ
λλ€. μ΄ μ½λμμλ Get λ©μλμμ μ½κΈ° λ½μ κ±Έκ³ , Set λ©μλμμ μ°κΈ° λ½μ κ±Έμ΄ data λ§΅μ μμ νκ² μ κ·Όνκ³ μμ ν μ μμ΅λλ€. μ½κΈ° λ½μ΄ νμν μ΄μ λ λ¨μν μ½κΈ° μμ
μ΄ λ§μ κ²½μ°, μ°κΈ° λ½μ κ±Έμ§ μκ³ μ½κΈ° λ½λ§ κ±Έμ΄ μ¬λ¬ κ³ λ£¨ν΄μ΄ λμμ μ½κΈ° μμ
μ μνν μ μλλ‘ νκΈ° μν¨μ
λλ€. μ΄λ₯Ό ν΅ν΄, κ΅³μ΄ μνμ λ³κ²½μ΄ μμ΄μ μ°κΈ° λ½μ κ±Έμ§ μμλ λλ κ²½μ°μλ μ½κΈ° λ½λ§ κ±Έμ΄ μ±λ₯μ ν₯μμν¬ μ μμ΅λλ€.
fakelock
fakelockμ sync.Lockerλ₯Ό ꡬννλ κ°λ¨ν νΈλ¦μ
λλ€. μ΄ κ΅¬μ‘°μ²΄λ sync.Mutexμ λμΌν λ©μλλ₯Ό μ 곡νμ§λ§, μ€μ λμμ νμ§ μμ΅λλ€.
1package fakelock
2
3type FakeLock struct{}
4
5func (f *FakeLock) Lock() {
6 // Questo metodo non esegue alcuna operazione di blocco reale.
7}
8
9func (f *FakeLock) Unlock() {
10 // Questo metodo non esegue alcuna operazione di sblocco reale.
11}
μ μ½λλ fakelock ν¨ν€μ§λ₯Ό ꡬνν μ½λμ
λλ€. μ΄ ν¨ν€μ§λ sync.Lockerλ₯Ό ꡬννμ¬ Lock, Unlock λ©μλλ₯Ό μ 곡νμ§λ§, μ€μ λ‘λ μ무 λμλ νμ§ μμ΅λλ€. μ μ΄λ¬ν μ½λκ° νμνμ§λ κΈ°νκ° λλ©΄ μμ νκ² μ΅λλ€.
waitgroup
sync.WaitGroup
sync.WaitGroupμ κ³ λ£¨ν΄μ μμ
μ΄ λͺ¨λ λλ λκΉμ§ κΈ°λ€λ¦¬λ λꡬμ
λλ€. Add, Done, Wait λ©μλλ₯Ό μ 곡νλ©°, Add λ©μλλ‘ κ³ λ£¨ν΄μ κ°μλ₯Ό μΆκ°νκ³ , Done λ©μλλ‘ κ³ λ£¨ν΄μ μμ
μ΄ λλ¬μμ μ립λλ€. κ·Έλ¦¬κ³ Wait λ©μλλ‘ λͺ¨λ κ³ λ£¨ν΄μ μμ
μ΄ λλ λκΉμ§ κΈ°λ€λ¦½λλ€.
1package main
2
3import (
4 "sync"
5 "sync/atomic"
6)
7
8func main() {
9 wg := sync.WaitGroup{}
10 c := atomic.Int64{}
11
12 for i := 0; i < 100 ; i++ {
13 wg.Add(1)
14 go func() {
15 defer wg.Done()
16 c.Add(1)
17 }()
18 }
19
20 wg.Wait()
21 println(c.Load())
22}
μ μ½λλ sync.WaitGroupμ μ¬μ©νμ¬ 100κ°μ κ³ λ£¨ν΄μ΄ λμμ c λ³μμ κ°μ λνλ μ½λμ
λλ€. μ΄ μ½λμμλ sync.WaitGroupμ μ¬μ©νμ¬ λͺ¨λ κ³ λ£¨ν΄μ΄ λλ λκΉμ§ κΈ°λ€λ¦° ν, c λ³μμ λν κ°μ μΆλ ₯ν©λλ€. λ¨μνκ² λͺλͺκ°μ μμ
μ fork & joinνλ κ²½μ°μ μ±λλ§μ μ΄μ©ν΄λ μΆ©λΆνμ§λ§, λ€λμ μμ
μ fork & joinνλ κ²½μ°μ sync.WaitGroupμ μ¬μ©νλ κ²λ μ’μ μ νμ§μ
λλ€.
with slice
μ¬λΌμ΄μ€μ ν¨κ» μ°μΈλ€λ©΄, waitgroupμ λ½ μμ΄ νλ₯ν λμ μ€ν μμ
μ κ΄λ¦¬νλ λκ΅¬κ° λ μ μμ΅λλ€.
1package main
2
3import (
4 "fmt"
5 "sync"
6 "rand"
7)
8
9func main() {
10 var wg sync.WaitGroup
11 arr := [10]int{}
12
13 for i := 0; i < 10; i++ {
14 wg.Add(1)
15 go func(id int) {
16 defer wg.Done()
17
18 arr[id] = rand.Intn(100)
19 }(i)
20 }
21
22 wg.Wait()
23 fmt.Println("Done")
24
25 for i, v := range arr {
26 fmt.Printf("arr[%d] = %d\n", i, v)
27 }
28}
μ μ½λλ waitgroupλ§μ μ¬μ©νμ¬ κ° κ³ λ£¨ν΄μ΄ λμμ 10κ°μ λλ€ μ μλ₯Ό μμ±νμ¬, ν λΉλ°μ μΈλ±μ€μ μ μ₯νλ μ½λμ
λλ€. μ΄ μ½λμμλ waitgroupμ μ¬μ©νμ¬ λͺ¨λ κ³ λ£¨ν΄μ΄ λλ λκΉμ§ κΈ°λ€λ¦° ν, Doneμ μΆλ ₯ν©λλ€. μ΄λ¬ν λ°©μμΌλ‘ waitgroupμ μ¬μ©νλ©΄, μ¬λ¬ κ³ λ£¨ν΄μ΄ λμμ μμ
μ μννκ³ , λͺ¨λ κ³ λ£¨ν΄μ΄ λλ λκΉμ§ λ½ μμ΄ λ°μ΄ν°λ₯Ό μ μ₯νκ³ , μμ
μ’
λ£ νμ μΌκ΄μ μΌλ‘ νμ²λ¦¬λ₯Ό ν μ μμ΅λλ€.
golang.org/x/sync/errgroup.ErrGroup
errgroupμ sync.WaitGroupμ νμ₯ν ν¨ν€μ§μ
λλ€. errgroupμ sync.WaitGroupκ³Ό λ¬λ¦¬, κ³ λ£¨ν΄μ μμ
μ€ νλλΌλ μλ¬κ° λ°μνλ©΄ λͺ¨λ κ³ λ£¨ν΄μ μ·¨μνκ³ μλ¬λ₯Ό λ°νν©λλ€.
1package main
2
3import (
4 "context"
5 "fmt"
6 "golang.org/x/sync/errgroup"
7)
8
9func main() {
10 g, ctx := errgroup.WithContext(context.Background())
11 _ = ctx
12
13 for i := 0; i < 10; i++ {
14 i := i
15 g.Go(func() error {
16 if i == 5 {
17 return fmt.Errorf("error")
18 }
19 return nil
20 })
21 }
22
23 if err := g.Wait(); err != nil {
24 fmt.Println(err)
25 }
26}
μ μ½λλ errgroupμ μ¬μ©νμ¬ 10κ°μ κ³ λ£¨ν΄μ μμ±νκ³ , 5λ²μ§Έ κ³ λ£¨ν΄μμ μλ¬λ₯Ό λ°μμν€λ μ½λμ
λλ€. μλμ μΌλ‘ λ€μ―λ²μ§Έ κ³ λ£¨ν΄μμ μλ¬λ₯Ό λ°μμμΌ, μλ¬κ° λ°μνλ κ²½μ°λ₯Ό 보μ¬λλ Έμ΅λλ€. λ€λ§ μ€μ λ‘ μ¬μ©ν λμλ errgroupμ μ¬μ©νμ¬ κ³ λ£¨ν΄μ μμ±νκ³ , κ° κ³ λ£¨ν΄μμ μλ¬κ° λ°μνλ κ²½μ°μ λν΄ λ€μν νμ²λ¦¬λ₯Ό μ§ννλ λ°©μμΌλ‘ μ¬μ©νλ©΄ λ©λλ€.
once
ν λ²λ§ μ€νλμ΄μΌ νλ μ½λλ₯Ό μ€ννλ λꡬμ λλ€. μλ μμ±μλ₯Ό ν΅ν΄ κ΄λ ¨ μ½λλ₯Ό μ€νν μ μμ΅λλ€.
1func OnceFunc(f func()) func()
2func OnceValue[T any](f func() T) func() T
3func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2)
OnceFunc
OnceFuncλ λ¨μν ν΄λΉ ν¨μκ° μ 체μ κ±Έμ³ λ± νλ²λ§ μ€νλ μ μκ² ν΄μ€λλ€.
1package main
2
3import "sync"
4
5func main() {
6 once := sync.OnceFunc(func() {
7 println("Hello, World!")
8 })
9
10 once()
11 once()
12 once()
13 once()
14 once()
15}
μ μ½λλ sync.OnceFuncμ μ¬μ©νμ¬ Hello, World!λ₯Ό μΆλ ₯νλ μ½λμ
λλ€. μ΄ μ½λμμλ sync.OnceFuncμ μ¬μ©νμ¬ once ν¨μλ₯Ό μμ±νκ³ , once ν¨μλ₯Ό μ¬λ¬ λ² νΈμΆν΄λ Hello, World!κ° ν λ²λ§ μΆλ ₯λ©λλ€.
OnceValue
OnceValueλ λ¨μν ν΄λΉ ν¨μκ° μ 체μ κ±Έμ³ λ± νλ²λ§ μ€νλλ κ²μ΄ μλλΌ, ν΄λΉ ν¨μμ λ°νκ°μ μ μ₯νμ¬ λ€μ νΈμΆν λ μ μ₯λ κ°μ λ°νν©λλ€.
1package main
2
3import "sync"
4
5func main() {
6 c := 0
7 once := sync.OnceValue(func() int {
8 c += 1
9 return c
10 })
11
12 println(once())
13 println(once())
14 println(once())
15 println(once())
16 println(once())
17}
μ μ½λλ sync.OnceValueλ₯Ό μ¬μ©νμ¬ c λ³μλ₯Ό 1μ© μ¦κ°μν€λ μ½λμ
λλ€. μ΄ μ½λμμλ sync.OnceValueλ₯Ό μ¬μ©νμ¬ once ν¨μλ₯Ό μμ±νκ³ , once ν¨μλ₯Ό μ¬λ¬ λ² νΈμΆν΄λ c λ³μκ° ν λ²λ§ μ¦κ°ν 1μ λ°νν©λλ€.
OnceValues
OnceValuesλ OnceValueμ λμΌνκ² μλνμ§λ§, μ¬λ¬ κ°μ λ°νν μ μμ΅λλ€.
1package main
2
3import "sync"
4
5func main() {
6 c := 0
7 once := sync.OnceValues(func() (int, int) {
8 c += 1
9 return c, c
10 })
11
12 a, b := once()
13 println(a, b)
14 a, b = once()
15 println(a, b)
16 a, b = once()
17 println(a, b)
18 a, b = once()
19 println(a, b)
20 a, b = once()
21 println(a, b)
22}
μ μ½λλ sync.OnceValuesλ₯Ό μ¬μ©νμ¬ c λ³μλ₯Ό 1μ© μ¦κ°μν€λ μ½λμ
λλ€. μ΄ μ½λμμλ sync.OnceValuesλ₯Ό μ¬μ©νμ¬ once ν¨μλ₯Ό μμ±νκ³ , once ν¨μλ₯Ό μ¬λ¬ λ² νΈμΆν΄λ c λ³μκ° ν λ²λ§ μ¦κ°ν 1μ λ°νν©λλ€.
atomic
atomic ν¨ν€μ§λ μμμ μ°μ°μ μ 곡νλ ν¨ν€μ§μ
λλ€. atomic ν¨ν€μ§λ Add, CompareAndSwap, Load, Store, Swap λ±μ λ©μλλ₯Ό μ 곡νμ§λ§, μ΅κ·Όμλ Int64, Uint64, Pointer λ±μ νμ
μ¬μ©μ κΆμ₯ν©λλ€.
1package main
2
3import (
4 "sync"
5 "sync/atomic"
6)
7
8func main() {
9 wg := sync.WaitGroup{}
10 c := atomic.Int64{}
11
12 for i := 0; i < 100 ; i++ {
13 wg.Add(1)
14 go func() {
15 defer wg.Done()
16 c.Add(1)
17 }()
18 }
19
20 wg.Wait()
21 println(c.Load())
22}
μκΉ μ°μλ μμ μ
λλ€. atomic.Int64 νμ
μ μ¬μ©νμ¬ c λ³μλ₯Ό μμμ μΌλ‘ μ¦κ°μν€λ μ½λμ
λλ€. Add λ©μλμ Load λ©μλλ‘ μμμ μΌλ‘ λ³μλ₯Ό μ¦κ°μν€κ³ , λ³μλ₯Ό μ½μ΄μ¬ μ μμ΅λλ€. λν Store λ©μλλ‘ κ°μ μ μ₯νκ³ , Swap λ©μλλ‘ κ°μ κ΅μ²΄νλ©°, CompareAndSwap λ©μλλ‘ κ°μ λΉκ΅ ν μ ν©νλ©΄ κ΅μ²΄ν μ μμ΅λλ€.
cond
sync.Cond
cond ν¨ν€μ§λ 쑰건 λ³μλ₯Ό μ 곡νλ ν¨ν€μ§μ
λλ€. cond ν¨ν€μ§λ sync.Condλ‘ μμ±ν μ μμΌλ©°, Wait, Signal, Broadcast λ©μλλ₯Ό μ 곡ν©λλ€.
1package main
2
3import (
4 "sync"
5)
6
7func main() {
8 c := sync.NewCond(&sync.Mutex{})
9 ready := false
10
11 go func() {
12 // Acquisisce il lock prima di modificare la condizione
13 c.L.Lock()
14 ready = true
15 // Segnala che la condizione Γ¨ stata soddisfatta
16 c.Signal()
17 c.L.Unlock()
18 }()
19
20 // Acquisisce il lock prima di attendere la condizione
21 c.L.Lock()
22 // Attende finchΓ© la condizione 'ready' non diventa vera
23 for !ready {
24 c.Wait()
25 }
26 c.L.Unlock()
27
28 println("Ready!")
29}
μ μ½λλ sync.Condλ₯Ό μ¬μ©νμ¬ ready λ³μκ° trueκ° λ λκΉμ§ κΈ°λ€λ¦¬λ μ½λμ
λλ€. μ΄ μ½λμμλ sync.Condλ₯Ό μ¬μ©νμ¬ ready λ³μκ° trueκ° λ λκΉμ§ κΈ°λ€λ¦° ν, Ready!λ₯Ό μΆλ ₯ν©λλ€. μ΄λ¬ν λ°©μμΌλ‘ sync.Condλ₯Ό μ¬μ©νλ©΄, μ¬λ¬ κ³ λ£¨ν΄μ΄ λμμ νΉμ 쑰건μ λ§μ‘±ν λκΉμ§ κΈ°λ€λ¦¬κ² ν μ μμ΅λλ€.
μ΄λ₯Ό νμ©νμ¬ κ°λ¨ν queueλ₯Ό ꡬνν μ μμ΅λλ€.
1package queue
2
3import (
4 "sync"
5 "sync/atomic"
6)
7
8type Node[T any] struct {
9 Value T
10 Next *Node[T]
11}
12
13type Queue[T any] struct {
14 sync.Mutex
15 Cond *sync.Cond
16 Head *Node[T]
17 Tail *Node[T]
18 Len int
19}
20
21func New[T any]() *Queue[T] {
22 q := &Queue[T]{}
23 // Inizializza Cond con il Mutex della coda
24 q.Cond = sync.NewCond(&q.Mutex)
25 return q
26}
27
28func (q *Queue[T]) Push(value T) {
29 q.Lock()
30 defer q.Unlock()
31
32 node := &Node[T]{Value: value}
33 if q.Len == 0 {
34 q.Head = node
35 q.Tail = node
36 } else {
37 q.Tail.Next = node
38 q.Tail = node
39 }
40 q.Len++
41 // Segnala a un goroutine in attesa che un elemento Γ¨ stato aggiunto
42 q.Cond.Signal()
43}
44
45func (q *Queue[T]) Pop() T {
46 q.Lock()
47 defer q.Unlock()
48
49 // Attende finchΓ© la coda non ha elementi
50 for q.Len == 0 {
51 q.Cond.Wait()
52 }
53
54 node := q.Head
55 q.Head = q.Head.Next
56 q.Len--
57 return node.Value
58}
μ΄λ κ² sync.Condλ₯Ό νμ©νλ©΄, spin-lockμΌλ‘ λ§μ CPU μ¬μ©λμ μ¬μ©νλ λμ μ ν¨μ¨μ μΌλ‘ λκΈ°νκ³ , μ‘°κ±΄μ΄ λ§μ‘±λλ©΄ λ€μ λμν μ μμ΅λλ€.
semaphore
golang.org/x/sync/semaphore.Semaphore
semaphore ν¨ν€μ§λ μΈλ§ν¬μ΄λ₯Ό μ 곡νλ ν¨ν€μ§μ
λλ€. semaphore ν¨ν€μ§λ golang.org/x/sync/semaphore.Semaphoreλ‘ μμ±ν μ μμΌλ©°, Acquire, Release, TryAcquire λ©μλλ₯Ό μ 곡ν©λλ€.
1package main
2
3import (
4 "context"
5 "fmt"
6 "golang.org/x/sync/semaphore"
7)
8
9func main() {
10 // Crea un nuovo semaforo pesato con una capacitΓ massima di 1
11 s := semaphore.NewWeighted(1)
12
13 // Tenta di acquisire un "peso" di 1 dal semaforo
14 if s.TryAcquire(1) {
15 fmt.Println("Acquired!")
16 } else {
17 fmt.Println("Not Acquired!")
18 }
19
20 // Rilascia un "peso" di 1 al semaforo
21 s.Release(1)
22}
μ μ½λλ semaphoreλ₯Ό μ¬μ©νμ¬ μΈλ§ν¬μ΄λ₯Ό μμ±νκ³ , μΈλ§ν¬μ΄λ₯Ό μ¬μ©νμ¬ Acquire λ©μλλ‘ μΈλ§ν¬μ΄λ₯Ό νλνκ³ , Release λ©μλλ‘ μΈλ§ν¬μ΄λ₯Ό ν΄μ νλ μ½λμ
λλ€. μ΄ μ½λμμλ semaphoreλ₯Ό μ¬μ©νμ¬ μΈλ§ν¬μ΄λ₯Ό νλνκ³ ν΄μ νλ λ°©λ²μ 보μ¬λλ Έμ΅λλ€.
λ§μΉλ©°
κΈ°λ³Έμ μΈ λ΄μ©μ μ¬κΈ°κΉμ§λ§ μμΌλ©΄ λ κ²κ°μ΅λλ€. μ΄ μν°ν΄μ λ΄μ©μ ν λλ‘, μ¬λ¬λΆλ€μ΄ κ³ λ£¨ν΄μ μ¬μ©νμ¬ λμμ±μ κ΄λ¦¬νλ λ°©λ²μ μ΄ν΄νκ³ , μ€μ λ‘ μ¬μ©ν μ μκ² λμ ¨μΌλ©΄ μ’κ² μ΅λλ€. μ΄ μν°ν΄μ΄ μ¬λ¬λΆλ€μκ² λμμ΄ λμμΌλ©΄ μ’κ² μ΅λλ€. κ°μ¬ν©λλ€.