2014-05-08 15 views
10

Supponiamo di avere una libreria di servizio con un metodo come questoReturn Task o attendono e ConfigureAwait (false)

public async Task<Person> GetPersonAsync(Guid id) { 
    return await GetFromDbAsync<Person>(id); 
} 

Seguendo le migliori pratiche per la SynchronizationContext è meglio usare

public async Task<Person> GetPersonAsync(Guid id) { 
    return await GetFromDbAsync<Person>(id).ConfigureAwait(false); 
} 

Ma quando hai una sola operazione (credo) è meglio restituire direttamente l'attività. Vedere At the end of an async method, should I return or await?

public Task<Person> GetPersonAsync(Guid id) { 
    return GetFromDbAsync<Person>(id); 
} 

In quest'ultimo caso non è possibile utilizzare ConfigureAwait (false) perché il metodo non è atteso.

Qual è la soluzione migliore (e perché)?

+1

Penso che l'ultima (delega) sia la più chiara e non implichi la creazione di una macchina di stato aggiuntiva. A meno che tu non stia facendo * qualcos'altro * all'interno del metodo che dipende dal risultato della chiamata asincrona, non vedo alcun motivo nell'usare 'await'. –

+0

L'ultimo ha più senso per me. Restituisce un'attività che puoi attendere da ovunque chiami GetPersonAsync –

+0

Quindi la soluzione che restituisce direttamente l'attività non acquisisce SynchronizationContext? – sevenmy

risposta

10

Ogni opzione ha le sue specifiche, controllare this e this. Se li capisci, potresti decidere qual è il migliore per te.

Quindi la soluzione che restituisce direttamente l'attività non acquisisce il SynchronizationContext ?

Non è il compito che cattura il contesto di sincronizzazione corrente. È TaskAwaiter.OnCompleted (o ConfiguredTaskAwaitable.OnCompleted, in caso di ConfigureAwait), che viene indirettamente richiamato dal codice generato dal compilatore C# come parte della dichiarazione await per l'attività.

Quindi, se non si utilizza await, non si dovrebbe essere preoccupati per la cattura dello SynchronizationContext, non si verifica magicamente da solo. Questo probabilmente rende la terza opzione la più favorevole, ma tieni presente il suo exception propagation behavior.

+0

grazie. Penso che questa sia una scelta molto specifica per il dominio. Fai qualche differenza se il metodo chiamato è veramente asincrono? Ad esempio una query asincrona con EF (la gestione degli errori è importante). – sevenmy

+1

Un'altra buona lettura è: [Prestazioni asincrone: Comprensione dei costi di Async e Attesa] (http://msdn.microsoft.com/en-us/magazine/hh456402.aspx) – sevenmy

+0

@sevenmy, Un metodo 'async Task' sarebbe non getta mai finché non osservi il compito con 'Attendi task',' task.Wait() ', o' task.Result'. OTOH, un metodo 'Task' non asincrono può essere lanciato immediatamente. ** Tuttavia **, nel codice cliente, non dovresti fare ipotesi. Il codice sempre come esso può essere lanciato in modo sincrono (sullo stesso frame dello stack) o in modo asincrono. – Noseratio

Problemi correlati