소개
이 랩은 여러 고루틴에서 접근하는 원자 카운터 (atomic counters) 를 위해 sync/atomic 패키지를 사용하여 Go 에서 상태를 관리하는 데 중점을 둡니다.
This tutorial is from open-source community. Access the source code
이 랩은 여러 고루틴에서 접근하는 원자 카운터 (atomic counters) 를 위해 sync/atomic 패키지를 사용하여 Go 에서 상태를 관리하는 데 중점을 둡니다.
문제는 50 개의 고루틴과 sync/atomic 패키지를 사용하여 카운터를 정확히 1000 번 증가시키는 것입니다.
sync/atomic 패키지를 사용하여 카운터를 증가시킵니다.## 우리는 정확히 50,000 번의 연산을 얻을 것으로 예상합니다. 만약
## 원자적이지 않은 `ops++` 를 사용하여 카운터를 증가시켰다면,
## 고루틴들이 서로 간섭하기 때문에
## 실행마다 다른 숫자를 얻을 가능성이 높습니다. 또한, `-race` 플래그로 실행할 때
## 데이터 경합 오류가 발생할 것입니다.
$ go run atomic-counters.go
ops: 50000
## 다음으로, 상태 관리를 위한 또 다른 도구인 뮤텍스 (mutex) 를 살펴보겠습니다.
전체 코드는 다음과 같습니다.
// Go 에서 상태를 관리하는 주요 메커니즘은
// 채널을 통한 통신입니다. 예를 들어
// [작업자 풀](worker-pools) 에서 이를 보았습니다. 하지만 상태를 관리하는 몇 가지 다른
// 옵션도 있습니다. 여기서는 여러 고루틴에서 접근하는 _원자 카운터_를 위해 `sync/atomic` 패키지를 사용하는 방법을
// 살펴보겠습니다.
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
// (항상 양수인) 카운터를 나타내기 위해 부호 없는 정수를 사용합니다.
var ops uint64
// WaitGroup 은 모든 고루틴이
// 작업을 완료할 때까지 기다리는 데 도움이 됩니다.
var wg sync.WaitGroup
// 각 카운터를 정확히 1000 번 증가시키는 50 개의 고루틴을 시작합니다.
for i := 0; i < 50; i++ {
wg.Add(1)
go func() {
for c := 0; c < 1000; c++ {
// 카운터를 원자적으로 증가시키기 위해
// `AddUint64` 를 사용하고, `&` 구문을 사용하여
// `ops` 카운터의 메모리 주소를 제공합니다.
atomic.AddUint64(&ops, 1)
}
wg.Done()
}()
}
// 모든 고루틴이 완료될 때까지 기다립니다.
wg.Wait()
// 다른 고루틴이 쓰고 있지 않다는 것을 알기 때문에
// 이제 `ops` 에 안전하게 접근할 수 있습니다. 업데이트되는 동안
// 원자성을 안전하게 읽는 것도
// `atomic.LoadUint64` 와 같은 함수를 사용하여 가능합니다.
fmt.Println("ops:", ops)
}
이 랩에서는 여러 고루틴을 사용하여 카운터를 증가시켜 Go 에서 상태를 관리하기 위해 sync/atomic 패키지를 사용하는 방법을 배웠습니다. AddUint64 함수는 카운터를 원자적으로 증가시키는 데 사용되었고, WaitGroup 은 모든 고루틴이 작업을 완료할 때까지 기다리는 데 사용되었습니다.