.NET 8 : Optimisation des recherches avec SearchValues et FrozenCollections
.NET 8 introduit SearchValues<T> et des collections comme FrozenSet<T>/FrozenDictionary<TKey, TValue>, qui réduisent drastiquement les surcoûts dans les chemins chauds. Ces structures effectuent le gros du travail lors de leur création, offrant des recherches en temps constant sans réanalyse répétée. Elles sont idéales pour les applications à fort débit traitant des millions d'opérations.
Accélérer la recherche de caractères avec SearchValues
La méthode standard string.IndexOfAny réanalyse l'ensemble de caractères à chaque appel, accumulant des surcoûts dans les boucles. SearchValues<char> est créée une seule fois et met en cache la stratégie de recherche optimale.
Lors de l'initialisation, .NET effectue :
- Analyse de l'ensemble d'entrée (caractère unique, plage ou multi-caractères).
- Sélection d'algorithme avec support SIMD (AVX2, SSE2).
- Construction de structures de données (masques de bits, tables de hachage).
SearchValues<char> separateurs = SearchValues.Create(".,;!?");
ReadOnlySpan<char> entree = "Hello, world!";
int index = entree.IndexOfAny(separateurs);
Les stratégies de recherche varient selon les données :
- Caractère unique — vérification vectorisée.
- Plage (0-9A-Z) — masque de bits en O(1).
- Petit ensemble (≤4 caractères) — SIMD.
- Grand ensemble — table de hachage optimisée.
Les benchmarks montrent des gains massifs :
| Scénario | IndexOfAny | SearchValues | Accélération |
|----------|------------|--------------|--------------|
| Chaîne courte | ~5 ns | ~5 ns | 1x |
| Chaîne longue (2000 caractères) | ~52 ns | ~4 ns | ~13x |
Les plus gros gains concernent les chaînes de plus de 100 caractères, évitant les réanalyses répétées.
FrozenCollections : Tables de hachage immuables
HashSet<T> et Dictionary<TKey, TValue> supportent des surcoûts de mutation comme le rehashing et les vérifications de limites. FrozenSet<T> et FrozenDictionary<TKey, TValue> sont optimisées pour les cas d'usage en lecture seule.
Lors de la création :
- Analyse des clés pour une fonction de hachage parfaite sans collisions.
- Disposition des données compatible avec le cache.
- Suppression des vérifications d'immutabilité à l'exécution.
Les petites collections utilisent des masques de bits au lieu du hachage.
var dict = Enumerable.Range(0, 100000)
.ToFrozenDictionary(x => x, x => $"Valeur {{x}}");
if (dict.TryGetValue(42, out string? valeur))
{
Console.WriteLine(valeur);
}
Benchmarks (100 000 éléments) :
| Opération | Dictionary | HashSet | FrozenDictionary | FrozenSet |
|-----------|------------|---------|------------------|-----------|
| TryGetValue/Contains | 3,78 ns | 4,47 ns | 1,87 ns | 3,37 ns |
FrozenDictionary est deux fois plus rapide qu'un Dictionary standard.
Cas d'usage réels
SearchValues :
- Des millions de recherches sur des ensembles fixes.
- Analyse de logs, tokenisation, validation.
- Chaînes longues (>100 caractères).
FrozenCollections :
- Configurations statiques chargées au démarrage.
- Tables de consultation (codes d'erreur, statuts).
- Charges de travail en lecture intensive avec des milliers de recherches.
Évitez-les pour des mutations fréquentes ou des appels rares — le coût de création l'emporte sur les bénéfices.
Mise en œuvre pratique
Mettez en cache au niveau de l'application :
public static class CacheApp
{
public static readonly SearchValues<char> CharsUrlSûrs =
SearchValues.Create("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~");
public static readonly FrozenSet<string> DevisesValides =
new[] { "USD", "EUR", "GBP", "JPY", "CNY" }.ToFrozenSet();
}
Exemples de validation :
- Email :
SearchValues<char> charsEmailInvalides = SearchValues.Create("()<>[]:;@\\,?\""); - TLD :
FrozenSet<string> tldsValides = ChargeTldsDepuisConfig().ToFrozenSet();
Profilez toujours avec BenchmarkDotNet — les gains dépendent du volume d'opérations.
Points clés
SearchValuesaccélère les recherches de 13x sur les longues chaînes grâce à une optimisation unique.FrozenDictionarydouble les performances deTryGetValuepar rapport àDictionary.- Les deux excellent avec des ensembles immuables dans les chemins chauds.
- Profilez d'abord : inutile pour les appels rares.
- Exploitez SIMD et le hachage parfait pour des victoires de développeurs intermédiaires/seniors.
— Editorial Team
Aucun commentaire pour le moment.