일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- CloudWatch
- kotlin querydsl
- 코틀린 코루틴의 정석
- mysql 튜닝
- Java
- CKA 기출문제
- 정보처리기사 실기
- APM
- CKA
- kotlin
- MySQL
- Pinpoint
- PETERICA
- 정보처리기사실기 기출문제
- minikube
- IntelliJ
- 기록으로 실력을 쌓자
- kotlin coroutine
- 정보처리기사 실기 기출문제
- Kubernetes
- 공부
- 오블완
- AI
- 티스토리챌린지
- aws
- Spring
- AWS EKS
- Elasticsearch
- Linux
- kotlin spring
- Today
- Total
피터의 개발이야기
[GO] Go 언어에서의 "fatal error: concurrent map read and map write" 해결하기 본문
[GO] Go 언어에서의 "fatal error: concurrent map read and map write" 해결하기
기록하는 백앤드개발자 2025. 2. 15. 09:37ㅁ 들어가며
ㅇ Go 개발자라면 한 번쯤 마주칠 수 있는 "fatal error: concurrent map read and map write" 오류에 대해 정리하였다. 이 오류는 동시성 프로그래밍에서 흔히 발생하는 문제로, 여러 고루틴이 동시에 맵을 읽고 쓰려고 할 때 발생한다.
또한, -race 플래그를 사용하면 Go의 레이스 디텍터로 프로그램을 테스트하면 이러한 동시성 문제를 사전에 발견하는 데 도움이 될 수 있다. 이 부분은 [GO] Go Race Detector: 동시성 버그를 잡아내는 강력한 도구에 정리하였다.
ㅁ 오류의 원인
이 오류는 Go의 맵이 기본적으로 동시성에 안전하지 않기 때문에 발생한다. 여러 고루틴이 동시에 같은 맵에 접근하여 읽기와 쓰기 작업을 수행할 때, Go 런타임은 이를 감지하고 프로그램을 중단시킨다.
ㅁ 해결 방법
이 문제를 해결하기 위한 몇 가지 방법을 찾아보았다.
sync.Mutex 사용
가장 간단한 방법은 sync.Mutex
를 사용하여 맵에 대한 접근을 동기화하는 것이다.
var mu sync.Mutex
m := make(map[string]int)
// 쓰기 작업
mu.Lock()
m["key"] = value
mu.Unlock()
// 읽기 작업
mu.Lock()
value := m["key"]
mu.Unlock()
sync.RWMutex 사용
읽기 작업이 많은 경우, sync.RWMutex
를 사용하여 성능을 개선할 수 있다.
var mu sync.RWMutex
m := make(map[string]int)
// 쓰기 작업
mu.Lock()
m["key"] = value
mu.Unlock()
// 읽기 작업
mu.RLock()
value := m["key"]
mu.RUnlock()
sync.Map 사용
Go 1.9 이후 버전에서는 sync.Map
을 사용할 수 있다. 이는 동시성에 안전한 맵 구현을 제공한다.
var m sync.Map
// 쓰기 작업
m.Store("key", value)
// 읽기 작업
value, ok := m.Load("key")
채널 사용
맵 접근을 단일 고루틴으로 제한하고 채널을 통해 통신하는 방법도 있다.
type SafeMap struct {
c chan command
m map[string]int
}
func NewSafeMap() *SafeMap {
sm := &SafeMap{
c: make(chan command),
m: make(map[string]int),
}
go sm.run()
return sm
}
func (sm *SafeMap) run() {
for cmd := range sm.c {
switch cmd.action {
case "write":
sm.m[cmd.key] = cmd.value
case "read":
cmd.result <- sm.m[cmd.key]
}
}
}
ㅁ Mutext와 sync.Map을 사용한 샘플코드
package main
import (
"fmt"
"sync"
)
func main() {
// Mutex를 사용한 방법
var counter = struct {
sync.RWMutex
m map[string]int
}{m: make(map[string]int)}
// 읽기
counter.RLock()
n := counter.m["some_key"]
counter.RUnlock()
fmt.Printf("Mutex - Read value: %d\n", n)
// 쓰기
counter.Lock()
counter.m["some_key"]++
counter.Unlock()
// sync.Map을 사용한 방법
var syncMap sync.Map
// 저장
syncMap.Store("some_key", 1)
// 읽기
value, ok := syncMap.Load("some_key")
if ok {
fmt.Printf("sync.Map - Read value: %v\n", value)
}
// 쓰기 (읽고 쓰기)
syncMap.Range(func(key, value interface{}) bool {
if k, ok := key.(string); ok && k == "some_key" {
if v, ok := value.(int); ok {
syncMap.Store(k, v+1)
}
}
return true
})
// 결과 확인
value, _ = syncMap.Load("some_key")
fmt.Printf("sync.Map - Updated value: %v\n", value)
}
ㅁ 마무리
동시성 프로그래밍에서 맵을 안전하게 사용하는 것은 중요하다. 상황에 따라 적절한 동기화 메커니즘을 선택하여 사용해야 한다.
동시성 문제를 해결할 때는 성능과 코드의 복잡성을 고려해야 한다. sync.Mutex
나 sync.RWMutex
는 간단하지만 성능 저하가 있을 수 있고, 채널을 사용한 방식은 성능은 좋지만 코드가 복잡해질 수 있다. 프로젝트의 요구사항에 맞는 최적의 솔루션을 선택하는 것이 중요하다.
ㅁ 함께 보면 좋은 사이트
ㅇ Map : concurrent 상황일 때 Read도 RLock을 해야 하는 이유
ㅇ Go 언어 개발의 동시성 및 동기화 문제를 해결하는 방법
ㄴ 뮤텍스 잠금, 채널 및 원자적 작업으로 동시성 해결방법 제시
ㅇ [Golang] fatal error: concurrent map writes
ㄴ 동시성 문제를 샘플코드로 Mutex, 채널이 코드 간결성과 성능의 차이를 설명함
'Programming > GO' 카테고리의 다른 글
[GO] Go 애플리케이션 메모리 사용량 증가 문제 해결 방법 (0) | 2025.02.11 |
---|---|
[GO] Golang에서 Viper 사용하기: 설정 관리 도구 (0) | 2025.01.10 |
[GO] Intel Xeon 프로세서 빌드 방법, GOOS, GOARCH 설정 (0) | 2024.12.06 |
[GO] Golang에서 http.Client를 이용한 프록시 설정방법 (0) | 2024.12.05 |
[GO] GO 언어란? 기본 문법 (2) | 2024.11.19 |