ConcurrentDictionary
ConcurrentDictionary는 .NET (C#)에서 멀티스레드 환경에서 안전하게 데이터를 읽고 쓸 수 있도록 설계된 스레드 안전한 딕셔너리(Dictionary)입니다.
기본적으로 Dictionary<TKey, TValue>는 단일 스레드 환경에서는 매우 빠르지만, 멀티스레드 환경에서는 동기화 처리가 필요합니다. 이를 수동으로 처리하는 대신, ConcurrentDictionary<TKey, TValue>를 사용하면 .NET이 내부적으로 락(lock)과 분할(lock striping) 기술을 통해 성능과 안전성을 보장합니다.
✅ 주요 특징
스레드 안전(Thread-safe) | 동시에 여러 스레드가 읽고/쓰기 가능 |
락 분할(Lock Striping) | 전체 딕셔너리에 락을 걸지 않고, 키 범위에 따라 분할하여 효율성 확보 |
성능 최적화 | 다중 코어 환경에서도 높은 처리 성능 |
Atomic 연산 지원 | AddOrUpdate, GetOrAdd 같은 연산이 원자적으로 수행됨 |
📦 네임스페이스 및 기본 구조
using System.Collections.Concurrent;
var dict = new ConcurrentDictionary<string, int>();
🛠️ 주요 메서드
TryAdd(key, value)
키가 존재하지 않을 때만 추가
bool added = dict.TryAdd("apple", 1);
TryGetValue(key, out value)
키가 있을 경우 값을 가져옴
if (dict.TryGetValue("apple", out int count))
{
Console.WriteLine(count);
}
TryUpdate(key, newValue, comparisonValue)
값이 예상한 값일 경우에만 업데이트
bool updated = dict.TryUpdate("apple", 5, 1); // apple 값이 1이면 5로 변경
AddOrUpdate(key, addValue, updateFunc)
존재하지 않으면 추가, 있으면 업데이트
int result = dict.AddOrUpdate("banana", 1, (key, oldValue) => oldValue + 1);
GetOrAdd(key, valueFactory)
존재하지 않으면 추가, 있으면 기존 값 반환
int val = dict.GetOrAdd("cherry", key => 10);
🧠 내부 동작
- 내부적으로 여러 개의 버킷(bucket)으로 나누고, 각 버킷마다 락을 걸어 동시 접근을 처리
- 일반 lock을 사용하는 것보다 훨씬 성능이 좋음
- foreach 사용 가능하지만, 컬렉션이 변할 수 있으므로 완전한 스냅샷이 아님
⚠️ 주의사항
- 순서 보장 없음 – 일반 Dictionary와 달리 순서를 보장하지 않음
- foreach 중 수정 가능 – 다른 스레드가 값을 추가/삭제할 수 있음 (예외 없음)
- Value 타입은 불변(immutable) 또는 안전하게 처리 필요 – 예: List 등 mutable 객체는 주의
🎯 언제 사용하나요?
- 다중 스레드 환경에서 공통 딕셔너리를 접근해야 할 때
- lock 사용 없이 간편하게 병렬 처리를 하고 싶을 때
- Task/ThreadPool 기반의 비동기 코드에서 공유 데이터를 다룰 때
🔚 결론
ConcurrentDictionary는 멀티스레드 환경에서 안전하게 사용 가능한 Dictionary입니다. 락 없이 성능 저하를 최소화하면서도 안전한 자료구조를 필요로 할 때 매우 유용합니다.
'UNITY > C#' 카테고리의 다른 글
[C#] /// 주석(XML 주석)의 역할 (0) | 2025.05.31 |
---|---|
리스트와 딕셔너리 (0) | 2024.11.22 |
=> 연산자 (람다 표현식) (0) | 2024.10.21 |
C# interface :: 'IEnumerator'와 'IEnumerable' (자료👀) (0) | 2024.06.25 |
C# Statements :: using, yield (0) | 2024.06.24 |