package main
import(
"fmt"
"math/rand"
"runtime"
"sync"
"sync/atomic"
"time"
)
func main() {
var state = make(map[int]int)
var mutex = &sync.Mutex{}
var ops int64 = 0
for r :=0; r < 100; r++ {
go func() {
total := 0
for {
key := rand.Intn(5)
mutex.Lock()
total += state[key]
mutex.Unlock()
atomic.AddInt64(&ops, 1)
runtime.Gosched()
}
}()
}
for w := 0; w < 10; w++ {
go func() {
for {
key := rand.Intn(5)
val := rand.Intn(100)
mutex.Lock()
state[key] = val
mutex.Unlock()
atomic.AddInt64(&ops, 1)
runtime.Gosched()
}
}()
}
time.Sleep(time.Second)
opsFinal := atomic.LoadInt64(&ops)
fmt.Println("ops:", opsFinal)
mutex.Lock()
fmt.Println("state:", state)
mutex.Unlock()
}
뮤텍스는 자원에 대한 접근을 한번에 하나씩제어하기 위해서 사용한다. 이 코드에서 관리할 자원은 map자료구조인 state다. 뮤텍스 객체는 sync.Mutex{}로 만들 수 있다.
18 ~ 31. 100개의 고루틴을 만들었다. 이 고루틴은 state로 부터 값을 읽어서 더하는 일을 한다. total += state[key]코드를 실행하기 위해서는 1. state로 부터 값을 읽어서 2. total과 더해서 저장해야 한다. 코드에 대한 원자적 연산을 보장하지 않는다면 state의 값을 읽어서 저장하기 전에, 다른 고루틴이 state의 값을 읽을 수 있다. 중복연산이 되는 셈이다. 이를 막기 위해서 mutex.Loc()와 mutex.Unlock()를 이용해서 하나의 고루틴만 진입하도록 설정했다.
33 ~ 45. 10개의 고루틴이 state에 값을 쓴다. 역시 뮤텍스를 이용해서 한번에 하나의 고루틴만 접근 할 수 있게 했다.
main 고루틴은 1초를 쉰 다음에, 그동안 연산했던 값들을 출력한다.
다음 예제 : Stateful Goroutines
예제로 살펴보는 Go : Mutexes
Recent Posts
Archive Posts
Tags