Optimalizace vyhledávání v .NET 8: SearchValues a FrozenCollections pro kritické cesty
V .NET 8 byly zavedeny SearchValues<T> a kolekce FrozenSet<T>/FrozenDictionary<TKey, TValue>, které minimalizují režii v kritických cestách. Tyto struktury provádějí těžkou optimalizaci při vytváření, zajišťují konstantní rychlost vyhledávání bez opakovaných analýz. Jsou vhodné pro vysoce zatížené aplikace s miliony operací.
Optimalizace vyhledávání znaků s SearchValues
Standardní string.IndexOfAny analyzuje sadu znaků při každém volání, což akumuluje režii v cyklech. SearchValues<char> se vytvoří jednou a ukládá optimální strategii vyhledávání.
Při inicializaci .NET provádí:
- Analýzu vstupní sady (jednotlivý znak, rozsah, množina).
- Výběr algoritmu s ohledem na SIMD (AVX2, SSE2).
- Vytvoření datových struktur (bitové masky, hash tabulky).
SearchValues<char> separators = SearchValues.Create(".,;!?");
ReadOnlySpan<char> input = "Hello, world!";
int index = input.IndexOfAny(separators);
Strategie vyhledávání závisí na datech:
- Jednotlivý znak — vektorová kontrola.
- Rozsah (0-9A-Z) — bitová maska O(1).
- Malá sada (≤4 znaky) — SIMD.
- Velká sada — optimalizovaná hash tabulka.
Benchmarky demonstrují zrychlení:
| Scénář | IndexOfAny | SearchValues | Zrychlení |
|----------|------------|--------------|-----------|
| Krátký řetězec | ~5 ns | ~5 ns | 1x |
| Dlouhý řetězec (2000 znaků) | ~52 ns | ~4 ns | ~13x |
Zisk je maximální pro řetězce >100 znaků díky vyloučení opakované analýzy.
FrozenCollections: nezmenitelné hash tabulky
HashSet<T> a Dictionary<TKey, TValue> nesou režii kvůli podpoře mutací: přehashování, kontroly hranic. FrozenSet<T> a FrozenDictionary<TKey, TValue> jsou optimalizovány pro read-only scénáře.
Při vytváření:
- Analýza klíčů pro perfect hash function bez kolizí.
- Cache-friendly umístění dat.
- Odstranění runtime-kontrol nezmenitelnosti.
Pro malé kolekce se použije bitová maska místo hashe.
var dict = Enumerable.Range(0, 100000)
.ToFrozenDictionary(x => x, x => $"Value {{x}}");
if (dict.TryGetValue(42, out string? value))
{
Console.WriteLine(value);
}
Benchmarky (100 000 prvků):
| Operace | Dictionary | HashSet | FrozenDictionary | FrozenSet |
|----------|------------|---------|------------------|-----------|
| TryGetValue/Contains | 3.78 ns | 4.47 ns | 1.87 ns | 3.37 ns |
FrozenDictionary je 2x rychlejší než standardní Dictionary.
Scénáře použití
SearchValues:
- Miliony vyhledávání ve fixní sadě.
- Parsování logů, tokenizace, validace.
- Dlouhé řetězce (>100 znaků).
FrozenCollections:
- Statické konfigurace při startu.
- Lookup-tabulky (kódy chyb, stavy).
- Read-heavy workloads s tisíci čtení.
Vyhněte se při častých mutacích nebo vzácných voláních — režie na vytváření převýší zisk.
Praktická implementace
Ukládejte na úrovni aplikace:
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();
}
Příklad validace:
- Email:
SearchValues<char> invalidEmailChars = SearchValues.Create("()<>[]:;@\\,?\""); - TLD:
FrozenSet<string> validTlds = LoadTldsFromConfig().ToFrozenSet();
Vždy ověřujte profilováním přes BenchmarkDotNet: návratnost závisí na objemu operací.
Co je důležité
SearchValueszrychluje vyhledávání 13x na dlouhých řetězcích díky jednorázové optimalizaci.FrozenDictionaryposkytuje 2x zlepšení v TryGetValue ve srovnání s Dictionary.- Oba nástroje jsou vhodné pro nezmenitelné sady v kritických cestách.
- Vyžadují profilování: nejsou efektivní pro vzácné volání.
- Podporují SIMD a perfect hashing pro middle/senior-vývojáře.
— Editorial Team
Zatím žádné komentáře.