Il codice asincrono rende le applicazioni reattive e scalabili, ma qualche errore ricorrente può causare blocchi, eccezioni perse o prestazioni peggiori del codice sincrono.
Regola 1: asincrono fino in fondo
Bloccare un Task con .Result o .Wait() spreca thread e, in alcuni contesti, provoca deadlock. Se un metodo chiama codice asincrono, deve diventare asincrono anche lui.
// Da evitare
var cliente = repo.TrovaAsync(id).Result;
// Corretto
var cliente = await repo.TrovaAsync(id);
Regola 2: niente async void
Un metodo async void non può essere atteso e le sue eccezioni non si possono intercettare con un normale try/catch. Si usa solo per i gestori di eventi; in tutti gli altri casi restituisci Task.
Regola 3: propaga il CancellationToken
public async Task<Report> GeneraAsync(int anno, CancellationToken ct)
{
var dati = await _repo.CaricaAsync(anno, ct);
return await _calcolo.ElaboraAsync(dati, ct);
}
Così una richiesta web annullata dall'utente interrompe davvero il lavoro, invece di continuare a consumare risorse.
Quando usare ValueTask
ValueTask evita un'allocazione quando il risultato è spesso già disponibile, per esempio letto da una cache:
public ValueTask<Prodotto?> TrovaAsync(int id)
{
if (_cache.TryGetValue(id, out var p))
return ValueTask.FromResult<Prodotto?>(p); // nessuna allocazione
return new ValueTask<Prodotto?>(CaricaDalDatabaseAsync(id));
}
Ma ha delle regole: un ValueTask si attende una sola volta e non va memorizzato per riusarlo. In caso di dubbio, Task resta la scelta più sicura; usa ValueTask solo dove una misura dimostra il vantaggio.
Commenti (0)
Nessun commento ancora.