.NET 8 검색 최적화: SearchValues와 FrozenCollections로 핫패스 가속
.NET 8에서 SearchValues<T>와 FrozenSet<T>/FrozenDictionary<TKey, TValue> 같은 컬렉션이 새로 등장했습니다. 이들은 핫패스에서 오버헤드를 대폭 줄여줍니다. 생성 시 모든 무거운 작업을 미리 처리해 상수 시간 조회를 제공하며, 반복 분석 없이 빠르게 동작합니다. 초당 수백만 건의 작업을 처리하는 고성능 앱에 딱 맞아요.
SearchValues로 문자 검색 속도 폭발
기존 string.IndexOfAny는 매 호출마다 문자 집합을 재분석해 루프에서 오버헤드가 쌓입니다. SearchValues<char>는 한 번 생성으로 최적 검색 전략을 캐싱합니다.
초기화 시 .NET이 수행하는 작업:
- 입력 집합 분석 (단일 문자, 범위, 다중 문자).
- SIMD 지원 알고리즘 선택 (AVX2, SSE2).
- 데이터 구조 구축 (비트마스크, 해시 테이블).
SearchValues<char> separators = SearchValues.Create(".,;!?");
ReadOnlySpan<char> input = "Hello, world!";
int index = input.IndexOfAny(separators);
데이터에 따라 검색 전략이 달라집니다:
- 단일 문자 — 벡터화 검사.
- 범위 (0-9A-Z) — O(1) 비트마스크.
- 소규모 집합 (≤4 문자) — SIMD.
- 대규모 집합 — 최적화된 해시 테이블.
벤치마크 결과 성능 향상이 뚜렷합니다:
| 시나리오 | IndexOfAny | SearchValues | 속도 향상 |
|----------|------------|--------------|----------|
| 짧은 문자열 | ~5 ns | ~5 ns | 1x |
| 긴 문자열 (2000자) | ~52 ns | ~4 ns | ~13x |
100자 이상 긴 문자열에서 반복 분석을 피할 때 가장 큰 효과를 봅니다.
FrozenCollections: 불변 해시 테이블
HashSet<T>와 Dictionary<TKey, TValue>는 리해싱과 경계 검사 같은 변경 오버헤드가 있습니다. FrozenSet<T>와 FrozenDictionary<TKey, TValue>는 읽기 전용에 최적화됐습니다.
생성 시:
- 충돌 없는 완벽 해시 함수를 위한 키 분석.
- 캐시 친화적 데이터 배치.
- 런타임 불변성 검사 제거.
작은 컬렉션은 해싱 대신 비트마스크를 씁니다.
var dict = Enumerable.Range(0, 100000)
.ToFrozenDictionary(x => x, x => $"Value {{x}}");
if (dict.TryGetValue(42, out string? value))
{
Console.WriteLine(value);
}
벤치마크 (10만 요소):
| 작업 | Dictionary | HashSet | FrozenDictionary | FrozenSet |
|------|------------|---------|------------------|-----------|
| TryGetValue/Contains | 3.78 ns | 4.47 ns | 1.87 ns | 3.37 ns |
FrozenDictionary가 일반 Dictionary보다 2배 빠릅니다.
실제 활용 사례
SearchValues:
- 고정 집합에 수백만 조회.
- 로그 파싱, 토큰화, 유효성 검사.
- 긴 문자열 (>100자).
FrozenCollections:
- 시작 시 로드하는 정적 설정.
- 조회 테이블 (에러 코드, 상태).
- 조회 중심 워크로드 (수천 건 조회).
자주 변경되거나 드물게 호출될 때는 생성 비용이 이득을 상쇄하니 피하세요.
실전 구현 팁
앱 레벨에서 캐싱하세요:
public static class AppCache
{
public static readonly SearchValues<char> UrlSafeChars =
SearchValues.Create("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~");
public static readonly FrozenSet<string> ValidCurrencies =
new[] { "USD", "EUR", "GBP", "JPY", "CNY" }.ToFrozenSet();
}
유효성 검사 예시:
- 이메일:
SearchValues<char> invalidEmailChars = SearchValues.Create("()<>[]:;@\\,?\""); - TLD:
FrozenSet<string> validTlds = LoadTldsFromConfig().ToFrozenSet();
항상 BenchmarkDotNet으로 프로파일링하세요. 작업량에 따라 이득이 달라집니다.
핵심 요약
SearchValues로 긴 문자열 검색 13배 빨라짐 (일회성 최적화).FrozenDictionary가Dictionary보다TryGetValue2배 빠름.- 핫패스 불변 집합에서 빛남.
- 프로파일링 필수: 드문 호출엔 무의미.
- SIMD와 완벽 해싱으로 미드/시니어 개발자 필수 기술.
— Editorial Team
아직 댓글이 없습니다.