공대생 정리노트
Map : concurrent 상황일 때 Read도 RLock을 해야 하는 이유 본문
레퍼런스
문제 상황
상황을 한번 가정해보자.
아무 key-value도 가지지 않는 Map을 가지고 있다고 해보자.
이 Map에 수많은 고루틴들이 랜덤으로 key를 넣어 Read를 시도한다.
만약 value가 있으면 그대로 가져오고, value가 없다면 랜덤으로 만든 value를 key-value 쌍으로 만들어 Map에 넣는다.
즉 각 고루틴은
1. Read를 시도
2. 없으면 Write
을 반복한다.
그렇다면 여기서 Write을 할 때는 Lock을 거는 것이 확실하다. 그런데 Read를 할 때도 Lock을 걸어야 할까?
즉, 한 고루틴이 Map[0]을 읽고 있는데 동시에 다른 고루틴이 Map[1]에 value를 write을 하는 것이 영향을 끼칠 수 있을까?
Map의 구조
Go Map은 채널이나 슬라이스보다 훨씬 복잡하다.
단순히 backing array를 보는 것이 아니라 internal state나 map iterator 등을 가지고 있다.
Map은 reference variable이 아닌 runtime.hmapstructure에 대한 포인터이다.
HashMap의 load factor가 일정 수준을 증가하면 HashMap의 성능이 줄어든다.
그래서 Go의 빌트인 자료구조들 중 오직 Map만 data를 내부적으로 움직인다.
Map은 O(1)을 보장하기 위해 insert나 delete시 리밸런스를 한다.
이러한 이유 때문에 Map의 value는 addressable하지 않다. (addressable이란? https://go.dev/ref/spec#Address_operators)
예를 들어 Map[1] = 2를 write하고, a = &Map[1]로 할당했다고 하자. 그럼 우리는 *a가 2의 값을 가질 것이라 생각할 것이다. 그러나 리밸런스가 되면 이것이 2를 가리키지 않을 수 있다는 것이다. Map[1]은 2를 여전히 가리키고 있겠지만.
그렇다면 어떻게 써야할까?
1. RWMutex를 이용하여 Map에서 Read를 할 때 RLock을 걸자
2. go 1.9버전 이후에는 sync.Map을 이용할 수 있다. 이걸 사용하자
'언어 > Go' 카테고리의 다른 글
defer - 실수하기 쉬운 인자 및 body의 값 계산 시점 (0) | 2022.03.19 |
---|---|
동시성 성능 테스트 mutex VS chan VS atomic (0) | 2021.12.19 |
파일 I/O - write과 read시 파일 lock이 있을까? (0) | 2021.12.08 |
Effective Go (2) 요약 (0) | 2021.11.01 |
Effective Go (1) 요약 (0) | 2021.10.18 |