2015-07-27 7 views
5

Ho una domanda riguardante l'attesa/asincronizzazione e l'utilizzo di metodi asincroni in scenari leggermente diversi dal previsto, ad esempio non direttamente in attesa. Per esempio, diciamo che ho due routine che ho bisogno di completare in parallelo, dove entrambi sono metodi asincroni (sono in attesa dentro). Sto usando await TAsk.WhenAll(...) che a sua volta si aspetta una sorta di elenco di attività da attendere. Quello che ho fatto è qualcosa di simile:Attendere/asincrare e uscire dalla casella

  await Task.WhenAll(new Task[] 
      { 
       Task.Run(async() => await internalLoadAllEmailTargets()), 
       Task.Run(async() => await internalEnumerateInvoices()) 
      }); 

Questo sembra eccessivamente elaborato per me, nel senso che sto creando compiti asincroni il cui unico scopo è quello di richiamare un altro compito. Non posso semplicemente usare le attività che vengono restituite dal motore di stato del metodo asincrono? Eppure, io non riuscendo a farlo dal momento che il compilatore tratta ogni menzione diretta di metodo asincrono come punto di invocazione:

  // this doesn't seem to work ok 
      await Task.WhenAll(new Task[] 
      { 
       internalLoadAllEmailTargets(), 
       internalEnumerateInvoices() 
      }); 

Se la sua in questo modo, sembra che le chiamate in modo sincrono uno dopo l'altro, e se ho posto attendo di fronte di metodi, non è più un compito. C'è qualche regola su come i metodi asincroni dovrebbero essere gestiti fuori dalla pianura attendono?

risposta

7

Ogni metodo async inizia a eseguire in modo sincrono, ma quando raggiunge il primo await, può comportarsi in modo asincrono. Quindi questa riga:

await Task.WhenAll(internalLoadAllEmailTargetsAsync(), internalEnumerateInvoicesAsync()); 

dovrebbe funzionare bene. È più o meno equivalente a questo:

var _1 = internalLoadAllEmailTargetsAsync(); 
var _2 = internalEnumerateInvoicesAsync(); 
await Task.WhenAll(_1, _2); 

Se i tuoi metodi sono veramente asincroni, allora dovrebbe andare bene.

Ora, se i tuoi metodi eseguono effettivamente un lavoro sincrono, ad esempio un codice con CPU elevato, puoi utilizzare lo Task.Run per richiamarli (se il tuo codice di chiamata si trova su un thread dell'interfaccia utente).

+0

Ah, ok, questo in realtà ha senso. Cosa succede se ho 'async Task ', quindi ho bisogno di raccogliere i risultati di più chiamate di metodi asincroni? – mmix

+0

@mmix: se entrambe le attività sono dello stesso tipo (ad esempio, "Attività "), allora puoi fare "Qualcosa [] risultati = attendere Task.WhenAll (...);" –

+0

Bene, non lo sono. Immagino di non andare in giro per i delegati. – mmix

1

Si dispone di un codice, che crea l'oggetto Task e verrà invocato come al solito, cioè in modo sincrono. Il controllo verrà restituito al codice di richiamo solo dopo la creazione di Task e nel caso di async sarà dopo il primo await. Quindi, se si tratta di un problema, alcune parti del metodo verranno richiamate in modo bloccante, è possibile utilizzare Task.Yield all'inizio, basta fare attenzione con SynchronizationContext e le opzioni di thread.

Ma nella maggior parte dei casi non c'è nulla di sbagliato in questo scenario, perché il codice, che crea Task, è piccolo e veloce, mentre il tempo reale è causato da una sorta di operazione IO.

Problemi correlati