| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 | 29 |
| 30 |
- aws
- CKA 기출문제
- CloudWatch
- PETERICA
- MySQL
- APM
- go
- kotlin coroutine
- Kubernetes
- 기록으로 실력을 쌓자
- Pinpoint
- 티스토리챌린지
- minikube
- AI
- tucker의 go 언어 프로그래밍
- golang
- 공부
- 바이브코딩
- Spring
- Linux
- kotlin
- 컨텍스트 엔지니어링
- SRE
- Java
- CKA
- 코틀린 코루틴의 정석
- AWS EKS
- kotlin querydsl
- 정보처리기사 실기 기출문제
- 오블완
- 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] Golang에서 Linux 명령어 실행 및 관리하기 (0) | 2025.02.17 |
|---|---|
| [GO] Go Race Detector: 동시성 버그를 잡아내는 강력한 도구 (0) | 2025.02.16 |
| [GO] Go 애플리케이션 메모리 사용량 증가 문제 해결 방법 (0) | 2025.02.11 |
| [GO] Golang에서 Viper 사용하기: 설정 관리 도구 (0) | 2025.01.10 |
| [GO] Intel Xeon 프로세서 빌드 방법, GOOS, GOARCH 설정 (0) | 2024.12.06 |