Serie · 4 articoli

LINQ, dal profiler al compilatore

Quattro errori trovati in produzione, i benchmark, e cosa genera davvero il compilatore

LINQ è dichiarativo, ma l'esecuzione è imperativa: la stessa sintassi nasconde costi radicalmente diversi a seconda della struttura dati sotto. La serie parte da un audit reale su un dispatcher di flotta con un budget di latenza sotto i 100ms, mette i numeri con BenchmarkDotNet, e scende fino alla state machine che il compilatore genera.

4
Articoli pubblicati
61
Minuti di lettura
Intermedio
Livello
.NETLINQPerformanceBenchmarkDotNetOpenTelemetry

Lo stesso codice, due ordini di grandezza di differenza

.Contains() su una List è O(n). .Contains() su un HashSet è O(1). Il codice che scrivete è identico. Il profiler racconta due storie diverse.

È il filo di tutta la serie: LINQ è dichiarativo, ma l'esecuzione è imperativa, e la stessa sintassi nasconde costi radicalmente diversi a seconda della struttura dati sotto. Il punto di partenza è un audit vero, su un dispatcher per una flotta di veicoli commerciali che tiene tutto in memoria per stare sotto i 100ms di latenza: quattro pattern trovati in produzione, e il più costoso faceva 1.400.000 confronti dove ne bastavano 2000.

Da li' la serie scende: i numeri misurati con BenchmarkDotNet invece che stimati, la state machine che il compilatore genera dietro una Where(), e infine come rendere visibile l'esecuzione con il tracing invece di doverla leggere nel codice.

Cosa imparerai

  • Riconoscere i quattro pattern che trasformano operazioni lineari in quadratiche
  • Misurare con BenchmarkDotNet invece di indovinare dove sta il costo
  • Capire cosa genera il compilatore dietro una Where(), e perché cambia il conto
  • Rendere visibile l'esecuzione con tracing, invece di leggerla nel codice

Articoli della serie

  1. 01
    4 Errori LINQ che Ho Trovato in Produzione (e Come Costavano 1000x) 17 min

    Quattro pattern LINQ che trasformano operazioni lineari in quadratiche, da un audit su un dispatcher di flotta con budget di latenza sotto i 100ms.

  2. 02
    Quanto Costa Davvero LINQ? Benchmark su .NET 8 con i Numeri 14 min

    Benchmark con BenchmarkDotNet su .NET 8: List contro HashSet fino a 63x, pipeline lazy con il 60% di allocazioni in meno, e il costo fisso di AsParallel.

  3. 03
    Cosa Genera il Compilatore Quando Scrivi una Where() — State Machine, Iteratori e IL 14 min

    Dietro ogni Where() c'è una state machine generata dal compilatore. In .NET 8 Enumerable.Where usa iteratori specializzati, e un cast li disattiva.

  4. 04
    Vedere LINQ in Azione: Tracing con OpenTelemetry e Grafana Tempo 16 min

    Rendere visibile l'esecuzione di LINQ con OpenTelemetry e Grafana Tempo: la waterfall mostra lo streaming, e OrderBy nel mezzo lo spezza.