Microsoft

Runtime Async in .NET 11 Preview 1: addio alle state machine del compilatore

Dario Fadda Maggio 27, 2026

Introduzione

Con il rilascio di .NET 11 Preview 1, Microsoft ha introdotto uno dei cambiamenti architetturali più significativi nella storia dell’async in .NET: il Runtime Async V2. Questo cambiamento sposta la responsabilità della gestione delle operazioni asincrone dal compilatore al runtime stesso, con impatti concreti su debug, profiling, leggibilità degli stack trace e potenzialmente sulle prestazioni.

In questo articolo analizziamo nel dettaglio come funziona il nuovo modello, come differisce dall’approccio attuale basato su state machine, come abilitarlo nei propri progetti e cosa aggiunge .NET 11 Preview 1 oltre al solo Runtime Async.

Il problema: le state machine del compilatore

Chiunque abbia lavorato seriamente con codice asincrono in C# conosce la frustrazione di leggere uno stack trace in produzione e trovarsi sommerso da frame generati dal compilatore. Ogni metodo async viene trasformato dal compilatore in una classe di stato (state machine) che implementa IAsyncStateMachine. Questa trasformazione è efficace, ma introduce livelli di indirezione che offuscano la reale catena di chiamate.

Un semplice stack di tre metodi async produce tipicamente oltre dieci frame nello stack trace live, la maggior parte appartenenti all’infrastruttura del compilatore (AsyncMethodBuilderCore.Start, ecc.). Il risultato è un debug più laborioso e strumenti di profiling che faticano a restituire una visione chiara dell’esecuzione.

Runtime Async V2: come funziona

Con Runtime Async, il compilatore non genera più la state machine. Emette invece un IL semplificato, annotato con [MethodImpl(MethodImplOptions.Async)], e delega al runtime la gestione della sospensione e ripresa dei metodi asincroni. In pratica, è il CLR stesso a tracciare l’esecuzione asincrona, non il codice generato dal compilatore.

Il risultato più visibile è nei live stack trace, ovvero ciò che profiler, debugger e new StackTrace() vedono durante l’esecuzione. Con Runtime Async, i metodi effettivi appaiono direttamente nello stack, senza wrapper di stato.

Confronto diretto degli stack trace

Consideriamo questo codice di esempio:

await OuterAsync();

static async Task OuterAsync()
{
    await Task.CompletedTask;
    await MiddleAsync();
}

static async Task MiddleAsync()
{
    await Task.CompletedTask;
    await InnerAsync();
}

static async Task InnerAsync()
{
    await Task.CompletedTask;
    Console.WriteLine(new StackTrace(fNeedFileInfo: true));
}

Senza Runtime Async — 13 frame, con tutta l’infrastruttura del compilatore visibile:

at Program.<<Main>$>g__InnerAsync|0_2() in Program.cs:line 24
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](...)
at Program.<<Main>$>g__InnerAsync|0_2()
at Program.<<Main>$>g__MiddleAsync|0_1() in Program.cs:line 14
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](...)
at Program.<<Main>$>g__MiddleAsync|0_1()
at Program.<<Main>$>g__OuterAsync|0_0() in Program.cs:line 8
...
(13 frame totali)

Con Runtime Async — 5 frame, la reale catena di chiamate:

at Program.<<Main>$>g__InnerAsync|0_2() in Program.cs:line 24
at Program.<<Main>$>g__MiddleAsync|0_1() in Program.cs:line 14
at Program.<<Main>$>g__OuterAsync|0_0() in Program.cs:line 8
at Program.<Main>$(String[] args) in Program.cs:line 3
at Program.<Main>(String[] args)

È importante notare che questo miglioramento riguarda i live stack trace. Gli exception stack trace (catch (Exception ex)) già apparivano in modo pulito grazie all’ExceptionDispatchInfo nelle versioni precedenti.

Miglioramenti al debugging

Con Runtime Async, il debugger può finalmente fare ciò che ci si aspetterebbe da sempre:

  • I breakpoint all’interno di metodi async si associano correttamente, senza essere deviati su codice generato
  • È possibile fare step-through attraverso i boundary degli await senza “saltare” nell’infrastruttura del compilatore
  • La finestra call stack del debugger mostra la catena reale, non i wrapper di stato

Questi miglioramenti avvantaggiano qualsiasi strumento che ispeziona lo stack live: profiler come dotTrace, logging diagnostico, e naturalmente il debugger integrato di Visual Studio e VS Code.

Come abilitare Runtime Async nel proprio progetto

Runtime Async è una feature in anteprima che richiede opt-in esplicito. Aggiungere le seguenti proprietà al file .csproj:

<PropertyGroup>
  <Features>runtime-async=on</Features>
  <EnablePreviewFeatures>true</EnablePreviewFeatures>
</PropertyGroup>

Ovviamente, essendo ancora in anteprima, non è consigliato per ambienti di produzione. È tuttavia un ottimo momento per sperimentarlo su branch di sviluppo e fornire feedback al team .NET.

Requisiti hardware aggiornati

.NET 11 alza il baseline hardware richiesto. Per x86/x64, il minimo passa da x86-64-v1 a x86-64-v2, richiedendo istruzioni aggiuntive come SSE3, SSSE3, SSE4.1, SSE4.2 e POPCNT. Questo rientra nei requisiti già imposti da Windows 11 e copre tutta l’hardware Intel/AMD attualmente supportato ufficialmente (i chip più vecchi sono usciti dal supporto intorno al 2013).

Per Arm64 su Windows, il baseline aggiunge ora il requisito dell’instruction set LSE, richiesto da Windows 11 e da tutti gli Arm64 supportati da Windows 10.

Altre novità di .NET 11 Preview 1

Supporto nativo a Zstandard

Le librerie guadagnano il supporto nativo alla compressione Zstandard tramite la nuova classe ZstandardStream. Zstandard offre rapporti di compressione migliori rispetto a gzip con velocità di decompressione molto elevate — un’aggiunta benvenuta per pipeline di dati e API ad alta frequenza.

BFloat16 per AI e ML

Arriva il tipo BFloat16 (Brain Float 16), un formato floating-point a 16 bit nato per carichi di lavoro di machine learning. È ampiamente usato da librerie AI come TensorFlow e PyTorch, e la sua presenza nativa in .NET facilita l’integrazione con modelli ML senza conversioni intermedie.

Miglioramenti JIT

  • Eliminazione dei bounds check: il JIT elimina ora i controlli ridondanti sul pattern i + cns < len, comune nei loop su array e Span
  • Rimozione di contesti checked ridondanti: quando un valore è già noto essere nel range, i controlli di overflow vengono rimossi
  • Devirtualizzazione in ReadyToRun: le immagini R2R possono ora devirtualizzare chiamate a virtual method generici non condivisi

Miglioramenti VM

Su piattaforme senza JIT (come iOS), l’interface dispatch ora usa un meccanismo di cache con miglioramenti di performance fino a 200x in codice ad alta intensità di interfacce. Guid.NewGuid() su Linux migliora del 12% circa usando la syscall getrandom() con batch caching.

C# 15: prime anticipazioni

.NET 11 Preview 1 include anche le prime feature di C# 15. Tra quelle già disponibili:

  • Collection expression arguments: possibilità di specificare capacità, comparatori o altri parametri del costruttore direttamente nella sintassi delle espressioni di collezione
  • Extended layout support: il compilatore emette TypeAttributes.ExtendedLayout per tipi annotati con ExtendedLayoutAttribute, principalmente per scenari di interop

Conclusione

Il Runtime Async V2 rappresenta un passo importante verso un’esperienza di sviluppo asincrono più trasparente e debuggabile in .NET. Non è ancora pronto per la produzione, ma la direzione è chiara: Microsoft vuole che gli sviluppatori smettano di combattere con stack trace incomprensibili e possano finalmente fare debug dell’async come del codice sincrono.

Con .NET 11 previsto per novembre 2026 come Standard Term Support (STS), c’è ancora tempo per sperimentare e contribuire al processo di feedback prima del rilascio finale.

Fonte: What’s new in the .NET 11 runtime — Microsoft Learn | InfoQ: .NET 11 Preview 1

💬 Unisciti alla discussione!


Questo è un blog del Fediverso: puoi trovare quindi questo articolo ovunque con @blog@spcnet.it e ogni commento/risposta apparirà qui sotto.

Se vuoi commentare su Runtime Async in .NET 11 Preview 1: addio alle state machine del compilatore, utilizza la discussione sul Forum.
Condividi la tua esperienza, confrontati con altri professionisti e approfondisci i dettagli tecnici nel nostro 👉 forum community