2014-11-03 13 views
5

Come creare un wrapper asincrono per il metodo sincrono?Modo per creare wrapper asincrono

// sync method 
public void LongOperation() 
{ 
    //code... 
} 


// versions of wrapper 
public async Task LongOpertionWrapperAsyncV1() 
{ 
    var task = Task.Factory.StartNew(LongOperation); 
    await task.ConfigureAwait(false); 
} 

public Task LongOpertionWrapperAsyncV2() 
{ 
    var task = Task.Factory.StartNew(LongOperation); 
    task.ConfigureAwait(false); 
    return task; 
} 

Sebbene l'uso di entrambe le versioni non differiscono.

async Task Executor() 
{ 
    await LongOpertionWrapperAsyncV1(); 
    await LongOpertionWrapperAsyncV2(); 
} 

Per i metodi che restituiscono il valore (Task <T>), io uso la prima versione.

Ma mi piacerebbe sapere la vostra opinione.

E c'è una differenza generale tra queste versioni?

+2

Per la cronologia: http://blogs.msdn.com/b/pfxteam/archive/2012/03/24/10287244.aspx – ken2k

+0

BTW, questo: 'task.ConfigureAwait (false);' non esegue *nulla*. 'ConfigureAwait()' * restituisce * un waiterver, se ignori il valore restituito, non avrà alcun effetto. – svick

risposta

4

Si dovrebbe usare "qualcosa come" V2:

public Task LongOpertionWrapperAsyncV2() 
{ 
    return Task.Run(LongOperation); 
} 

e

async Task Executor() 
{ 
    await LongOpertionWrapperAsyncV2().ConfigureAwait(false); 
} 

Ciò consente di risparmiare un contesto-switch rispetto a V1. Finché non è necessario "attendere un'altra operazione" e l'attività asincrona è l'ultima operazione del metodo, è sufficiente restituire l'attività anziché attendere e lasciare l'attesa al chiamante (che può anche o non può aggiungere ConfigureAwait).

Task.Factory.StartNew è necessario solo se si desidera fornire TaskCreationOptions.LongRunning come suggerito HPT.

UPDATE:
Come Stephen già meantioned: ci sono pochissimi casi in cui si dovrebbe fare async over sync (ma ce ne sono). Quindi pensa a cosa stai facendo esattamente prima di implementare qualcosa di simile. Semplificato detto: Se è un lavoro legato alla CPU NON farlo, se è una sorta di "attesa di IO" FORSE farlo.
Abbiamo un caso qui in cui abbiamo sviluppato una libreria "quasi asincrono tutto il modo", che consiste nel controllare diversi dispositivi HW. C'è tutta la "libreria generico" è asincrona, ma alcuni dei driver di periferica di basso livello e/o librerie di accesso non supportano async così al livello molto più basso che facciamo qualcosa di simile:

public async Task<byte[]> ReadAsync(int length) 
{ 
    return Task.Run(() => hwDevice.Read(length)); 
} 

Il hwDevice.Read fa ancora bloccare il thread, ma non la CPU, quindi l'interfaccia utente è reattiva in quel momento stiamo aspettando l'I/O (nel "live reale" ci sono anche alcune regole di cancellazione e gestione degli errori attorno ad esso).

14

Neither solution is correct. La migliore risposta è non esporre metodi asincroni per il codice sincrono. Vado più nel "perché" on my blog.

Se il codice è asincrono, utilizzare async e await. Se non lo è, allora non farlo. Dovrebbe essere al chiamante il modo in cui desiderano richiamare il codice (ad esempio, utilizzando Task.Run).

+0

Esiste un modo corretto per avvolgere un metodo sincrono che dovrebbe essere asincrono asincrono? cioèSupponiamo che tu abbia il metodo sincrono, GetDatabaseData(); poiché le chiamate DB sono vincolate all'I/O, esiste un mezzo per rendere questo asincrono? – Mackers

+1

@Mackers: No. Se il metodo non è asincrono, non c'è modo di "renderlo" asincrono (a meno che tu non modifichi l'implementazione, ovviamente). –

+0

@StephenCleary Ho letto il tuo post "Non bloccare su Async". Cosa succede se voglio creare un wrapper sincrono del metodo asincrono? Dovrei usare 'ConfigureAwait' nei miei metodi sincroni (wrapper di async)? – lll