6

Ultimamente ho riscontrato alcune situazioni in cui i metodi async vengono eseguiti in modo sincrono, ma restituiscono comunque un'attività, in modo che possano essere attesi, ad es.Task.FromResult() vs. Task.Run()

public virtual Task CreateAsync(TUser user) 
{ 
    ThrowIfDisposed(); 
    if (user == null) throw new ArgumentNullException("user"); 
    Context.Save(user); 
    Context.Flush(); 
    return Task.FromResult(0); 
} 

Sicuramente è meglio inviare l'operazione probabilmente a lungo-in esecuzione ad un filo e restituire il compito ancora attivo, per essere effettivamente atteso:

public virtual Task CreateAsync(TUser user) 
{ 
    ThrowIfDisposed(); 
    if (user == null) throw new ArgumentNullException("user"); 
    return Task.Run(() => 
    { 
     Context.Save(user); 
     Context.Flush(); 
    }); 
} 

ho qualche sospetto, però, che solo la filatura dei fili TPL non è la pratica più sicura. Qualche commento su questi due diversi modelli?

+0

Se possibile, è necessario chiamare un metodo asincrono effettivo anziché uno di questi. – SLaks

+0

@SLaks In che modo il secondo non è asincrono (oltre a non usare una nuova parola chiave)? (proveniente da qualcuno che non usa spesso le funzioni asincrone) –

+0

@KyleW: Spreca ancora un thread. Vedi http://blog.slaks.net/2014-12-23/parallelism-async-threading-explained/ – SLaks

risposta

10

Se il metodo è sincrono, non è necessario restituire Task all'inizio. Basta creare un metodo sincrono tradizionale.

Se per qualche motivo che non è possibile (ad esempio, si sceglie di implementare alcune interfaccia asincrona) restituendo un'attività completata utilizzando Task.FromResult o ancora meglio in questo caso Task.CompletedTask (aggiunto in .NET 4.6) è molto meglio che usare Task.Run nell'attuazione :

public virtual Task CreateAsync(TUser user) 
{ 
    // ... 
    return Task.CompletedTask; 
} 

Se il consumatore del vostro API preoccupa fortemente sul metodo Task -returning non è in esecuzione in modo sincrono possono usare Task.Run se stessi per assicurarsi.

Si dovrebbe tenere presente che i metodi asincroni possono avere una considerevole parte sincrona (la parte prima della prima attesa) anche se alla fine continuano in modo asincrono. Non si può presumere che i metodi asincroni restituiscano immediatamente un valore Task.

5

Task.FromResult in realtà non crea o esegue un'attività ma racchiude semplicemente il risultato restituito in un oggetto compito. Personalmente l'ho usato in Unit Tests dove ho bisogno di simulare i metodi Async e naturalmente non vorrei eseguire attività reali nei test di Unità.

Oltre a Task.Run verrà effettivamente creata un'attività ed eseguita un'attività su TaskScheduler. Non è consigliabile utilizzare Task.Run quando si esegue la programmazione Async. Piuttosto usa await per le attività. Vedi alcuni do's and don't of Tasks di Stephen Cleary.

Problemi correlati