sync/atomic 패키지를 사용하여 안전하게 수치 계산하기
8535 단어 Go
여기에 여러 개의 Gooroutine이 한 개의 수치만 10000번 계수하는 실제 장치를 비교합니다.
TL;DR
수치의 계수를 안전하게 진행하기 위해 sync/atomic
패키지의 atomic.AddUint32()
등 함수를 사용합니다.
기준 환경
다음과 같은 환경에서 대략적인 측정을 진행한다.
CPU는 4코어입니다.
비교할 코드
++ 연산자를 고려할 필요가 없습니다
func useIncrementOperator() uint32 {
var cnt uint32
var wg sync.WaitGroup
for i := 0; i < times; i++ {
wg.Add(1)
go func() {
cnt++
wg.Done()
}()
}
wg.Wait()
return cnt
}
sync/atomic 포장된 atomic.AddUint 32 사용()
func useAtomicAddUint32() uint32 {
var cnt uint32
var wg sync.WaitGroup
for i := 0; i < times; i++ {
wg.Add(1)
go func() {
atomic.AddUint32(&cnt, 1)
wg.Done()
}()
}
wg.Wait()
return cnt
}
sync 포장된 sync.Mutex 사용
func useSyncMutexLock() uint32 {
var cnt uint32
var wg sync.WaitGroup
mu := new(sync.Mutex)
for i := 0; i < times; i++ {
wg.Add(1)
go func() {
mu.Lock()
defer mu.Unlock()
cnt++
wg.Done()
}()
}
wg.Wait()
return cnt
}
실행하다
그럼 이 코드를 실제로 실행해서 결과를 비교해 봅시다.
코드 전체가 여기.에 있습니다.$ go run main.go
GOMAXPROCS: 1
useIncrementOperator(): 10000
useAtomicAddUint32(): 10000
useSyncMutexLock(): 10000
하나하나가 모두 10000에 이르렀다.
언뜻 보기에는 별 문제가 없는 것 같지만 GOMAXPROCS를 설정해서 여러 개의 핵심을 사용해 보겠습니다.$ GOMAXPROCS=4 go run main.go
GOMAXPROCS: 4
useIncrementOperator(): 9637
useAtomicAddUint32(): 10000
useSyncMutexLock(): 10000
간단히++
연산자 사용의 실현은 일치하지 않는다.
병렬 처리를 할 때++
는 연산자로 가산점을 할 수 없다는 것을 안다.
이 질문-race
도 옵션을 사용하여 확인할 수 있습니다.$ go run -race main.go
GOMAXPROCS: 1
==================
WARNING: DATA RACE
Read by goroutine 6:
main.func·001()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:19 +0x43
Previous write by goroutine 5:
main.func·001()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:19 +0x57
Goroutine 6 (running) created at:
main.useIncrementOperator()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:21 +0x14d
main.main()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:69 +0x12a
Goroutine 5 (finished) created at:
main.useIncrementOperator()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:21 +0x14d
main.main()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:69 +0x12a
==================
useIncrementOperator(): 10000
useAtomicAddUint32(): 10000
useSyncMutexLock(): 10000
Found 1 data race(s)
exit status 66
벤치 표시를 해볼게요.
다음은 atomic.AddUint32()
와 sync.Mutex
중 어느 것이 더 빠른지 비교해 봅시다.
이것도 전체 코드여기.입니다.$ GOMAXPROCS=1 go test -bench .
testing: warning: no tests to run
PASS
BenchmarkUseIncrementOperator 200 9204798 ns/op
BenchmarkUseAtomicAddUint64 200 9354682 ns/op
BenchmarkUseSyncMutexLock 100 12104668 ns/op
ok github.com/yuya-takeyama/go-practice/sync/counter 6.453s
GOMAXPROCS=1
상태에서 사용하는 방법sync.Mutex
은 사용하는 방법atomic.AddUint32()
보다 1.3배 빠르다.
다음GOMAXPROCS=4
실행해 봅시다.$ GOMAXPROCS=4 go test -bench .
testing: warning: no tests to run
PASS
BenchmarkUseIncrementOperator-4 300 4242947 ns/op
BenchmarkUseAtomicAddUint64-4 300 4207403 ns/op
BenchmarkUseSyncMutexLock-4 200 6745847 ns/op
ok github.com/yuya-takeyama/go-practice/sync/counter 5.496s
물론 시행 시간이 빨라졌지만 1.3배였던 시행 시간 차이는 1.6배에 달했다.
병렬도가 높을수록 록의 대기 시간은 길어진다.
Reference
이 문제에 관하여(sync/atomic 패키지를 사용하여 안전하게 수치 계산하기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/yuya_takeyama/items/98e5a9fe6786df11c8a7
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
다음과 같은 환경에서 대략적인 측정을 진행한다.
CPU는 4코어입니다.
비교할 코드
++ 연산자를 고려할 필요가 없습니다
func useIncrementOperator() uint32 {
var cnt uint32
var wg sync.WaitGroup
for i := 0; i < times; i++ {
wg.Add(1)
go func() {
cnt++
wg.Done()
}()
}
wg.Wait()
return cnt
}
sync/atomic 포장된 atomic.AddUint 32 사용()
func useAtomicAddUint32() uint32 {
var cnt uint32
var wg sync.WaitGroup
for i := 0; i < times; i++ {
wg.Add(1)
go func() {
atomic.AddUint32(&cnt, 1)
wg.Done()
}()
}
wg.Wait()
return cnt
}
sync 포장된 sync.Mutex 사용
func useSyncMutexLock() uint32 {
var cnt uint32
var wg sync.WaitGroup
mu := new(sync.Mutex)
for i := 0; i < times; i++ {
wg.Add(1)
go func() {
mu.Lock()
defer mu.Unlock()
cnt++
wg.Done()
}()
}
wg.Wait()
return cnt
}
실행하다
그럼 이 코드를 실제로 실행해서 결과를 비교해 봅시다.
코드 전체가 여기.에 있습니다.$ go run main.go
GOMAXPROCS: 1
useIncrementOperator(): 10000
useAtomicAddUint32(): 10000
useSyncMutexLock(): 10000
하나하나가 모두 10000에 이르렀다.
언뜻 보기에는 별 문제가 없는 것 같지만 GOMAXPROCS를 설정해서 여러 개의 핵심을 사용해 보겠습니다.$ GOMAXPROCS=4 go run main.go
GOMAXPROCS: 4
useIncrementOperator(): 9637
useAtomicAddUint32(): 10000
useSyncMutexLock(): 10000
간단히++
연산자 사용의 실현은 일치하지 않는다.
병렬 처리를 할 때++
는 연산자로 가산점을 할 수 없다는 것을 안다.
이 질문-race
도 옵션을 사용하여 확인할 수 있습니다.$ go run -race main.go
GOMAXPROCS: 1
==================
WARNING: DATA RACE
Read by goroutine 6:
main.func·001()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:19 +0x43
Previous write by goroutine 5:
main.func·001()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:19 +0x57
Goroutine 6 (running) created at:
main.useIncrementOperator()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:21 +0x14d
main.main()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:69 +0x12a
Goroutine 5 (finished) created at:
main.useIncrementOperator()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:21 +0x14d
main.main()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:69 +0x12a
==================
useIncrementOperator(): 10000
useAtomicAddUint32(): 10000
useSyncMutexLock(): 10000
Found 1 data race(s)
exit status 66
벤치 표시를 해볼게요.
다음은 atomic.AddUint32()
와 sync.Mutex
중 어느 것이 더 빠른지 비교해 봅시다.
이것도 전체 코드여기.입니다.$ GOMAXPROCS=1 go test -bench .
testing: warning: no tests to run
PASS
BenchmarkUseIncrementOperator 200 9204798 ns/op
BenchmarkUseAtomicAddUint64 200 9354682 ns/op
BenchmarkUseSyncMutexLock 100 12104668 ns/op
ok github.com/yuya-takeyama/go-practice/sync/counter 6.453s
GOMAXPROCS=1
상태에서 사용하는 방법sync.Mutex
은 사용하는 방법atomic.AddUint32()
보다 1.3배 빠르다.
다음GOMAXPROCS=4
실행해 봅시다.$ GOMAXPROCS=4 go test -bench .
testing: warning: no tests to run
PASS
BenchmarkUseIncrementOperator-4 300 4242947 ns/op
BenchmarkUseAtomicAddUint64-4 300 4207403 ns/op
BenchmarkUseSyncMutexLock-4 200 6745847 ns/op
ok github.com/yuya-takeyama/go-practice/sync/counter 5.496s
물론 시행 시간이 빨라졌지만 1.3배였던 시행 시간 차이는 1.6배에 달했다.
병렬도가 높을수록 록의 대기 시간은 길어진다.
Reference
이 문제에 관하여(sync/atomic 패키지를 사용하여 안전하게 수치 계산하기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/yuya_takeyama/items/98e5a9fe6786df11c8a7
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
func useIncrementOperator() uint32 {
var cnt uint32
var wg sync.WaitGroup
for i := 0; i < times; i++ {
wg.Add(1)
go func() {
cnt++
wg.Done()
}()
}
wg.Wait()
return cnt
}
func useAtomicAddUint32() uint32 {
var cnt uint32
var wg sync.WaitGroup
for i := 0; i < times; i++ {
wg.Add(1)
go func() {
atomic.AddUint32(&cnt, 1)
wg.Done()
}()
}
wg.Wait()
return cnt
}
func useSyncMutexLock() uint32 {
var cnt uint32
var wg sync.WaitGroup
mu := new(sync.Mutex)
for i := 0; i < times; i++ {
wg.Add(1)
go func() {
mu.Lock()
defer mu.Unlock()
cnt++
wg.Done()
}()
}
wg.Wait()
return cnt
}
그럼 이 코드를 실제로 실행해서 결과를 비교해 봅시다.
코드 전체가 여기.에 있습니다.
$ go run main.go
GOMAXPROCS: 1
useIncrementOperator(): 10000
useAtomicAddUint32(): 10000
useSyncMutexLock(): 10000
하나하나가 모두 10000에 이르렀다.언뜻 보기에는 별 문제가 없는 것 같지만 GOMAXPROCS를 설정해서 여러 개의 핵심을 사용해 보겠습니다.
$ GOMAXPROCS=4 go run main.go
GOMAXPROCS: 4
useIncrementOperator(): 9637
useAtomicAddUint32(): 10000
useSyncMutexLock(): 10000
간단히++
연산자 사용의 실현은 일치하지 않는다.병렬 처리를 할 때
++
는 연산자로 가산점을 할 수 없다는 것을 안다.이 질문
-race
도 옵션을 사용하여 확인할 수 있습니다.$ go run -race main.go
GOMAXPROCS: 1
==================
WARNING: DATA RACE
Read by goroutine 6:
main.func·001()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:19 +0x43
Previous write by goroutine 5:
main.func·001()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:19 +0x57
Goroutine 6 (running) created at:
main.useIncrementOperator()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:21 +0x14d
main.main()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:69 +0x12a
Goroutine 5 (finished) created at:
main.useIncrementOperator()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:21 +0x14d
main.main()
/Users/yuya/src/github.com/yuya-takeyama/go-practice/sync/counter/main.go:69 +0x12a
==================
useIncrementOperator(): 10000
useAtomicAddUint32(): 10000
useSyncMutexLock(): 10000
Found 1 data race(s)
exit status 66
벤치 표시를 해볼게요.
다음은 atomic.AddUint32()
와 sync.Mutex
중 어느 것이 더 빠른지 비교해 봅시다.
이것도 전체 코드여기.입니다.$ GOMAXPROCS=1 go test -bench .
testing: warning: no tests to run
PASS
BenchmarkUseIncrementOperator 200 9204798 ns/op
BenchmarkUseAtomicAddUint64 200 9354682 ns/op
BenchmarkUseSyncMutexLock 100 12104668 ns/op
ok github.com/yuya-takeyama/go-practice/sync/counter 6.453s
GOMAXPROCS=1
상태에서 사용하는 방법sync.Mutex
은 사용하는 방법atomic.AddUint32()
보다 1.3배 빠르다.
다음GOMAXPROCS=4
실행해 봅시다.$ GOMAXPROCS=4 go test -bench .
testing: warning: no tests to run
PASS
BenchmarkUseIncrementOperator-4 300 4242947 ns/op
BenchmarkUseAtomicAddUint64-4 300 4207403 ns/op
BenchmarkUseSyncMutexLock-4 200 6745847 ns/op
ok github.com/yuya-takeyama/go-practice/sync/counter 5.496s
물론 시행 시간이 빨라졌지만 1.3배였던 시행 시간 차이는 1.6배에 달했다.
병렬도가 높을수록 록의 대기 시간은 길어진다.
Reference
이 문제에 관하여(sync/atomic 패키지를 사용하여 안전하게 수치 계산하기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/yuya_takeyama/items/98e5a9fe6786df11c8a7
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
$ GOMAXPROCS=1 go test -bench .
testing: warning: no tests to run
PASS
BenchmarkUseIncrementOperator 200 9204798 ns/op
BenchmarkUseAtomicAddUint64 200 9354682 ns/op
BenchmarkUseSyncMutexLock 100 12104668 ns/op
ok github.com/yuya-takeyama/go-practice/sync/counter 6.453s
$ GOMAXPROCS=4 go test -bench .
testing: warning: no tests to run
PASS
BenchmarkUseIncrementOperator-4 300 4242947 ns/op
BenchmarkUseAtomicAddUint64-4 300 4207403 ns/op
BenchmarkUseSyncMutexLock-4 200 6745847 ns/op
ok github.com/yuya-takeyama/go-practice/sync/counter 5.496s
Reference
이 문제에 관하여(sync/atomic 패키지를 사용하여 안전하게 수치 계산하기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/yuya_takeyama/items/98e5a9fe6786df11c8a7텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)