2015-10-15 10 views
5

Devo mancare qualcosa di ovvio, come una situazione di stallo sul SynchronizationContext, ma non vedo il motivo per cui accade, e non capisco come posso evitarlo ...Task.WaitAll si blocca con async/attendere compiti

Quindi, l'applicazione è Azure WorkerRole (essenzialmente, per quanto ho capito, la normale app di Windows senza interfaccia utente). Nella domanda, sto cercando di parallelo l'esecuzione di una serie di compiti, e la versione schematica del mio codice è questo:

private async Task DoJob() 
{ 
    await SomeIoOperation(); 
} 


public void MethodExecutedByWorkerRoleInAnInfiniteLoop() 
{ 
    Log("Start"); 
    Task.WaitAll(DoJob(), DoJob(), DoJob()); 
    Log("End"); 
} 

La mia idea è che ci troviamo ad operare con predefinito SynchronizationContext qui, quindi dovremmo evitare il deadlock che avremmo in situazioni simili, ad esempio, ASP.NET.

Tuttavia, a volte l'esecuzione di si blocca - Avvio registrato, Fine non per i giorni fino a quando non si riavvia il ruolo di lavoratore. Naturalmente, non c'è modo in cui DoJob potrebbe essere in esecuzione così a lungo. Stranamente, questo non accade immediatamente dopo l'inizio del ruolo di lavoratore - potrebbero essere necessari giorni o settimane di normale funzionamento fino a quando non si blocca.

Potrei semplificare troppo il codice - forse è importante cosa succede esattamente in SomeIoOperation - ma ritengo che questo sia qualcosa di ovvio relativo all'uso improprio di SynchronizationContext.

aiuto SomeIoOperation.ConfigureAwait(false)? Non riesco nemmeno a verificarlo, perché non so se funziona perché il problema è stato risolto, o alla fine si bloccerà dopo qualche giorno in più.

Idee?

+1

Questo articolo ti illuminerà sulla causa http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html – Gusdor

+2

Aggiungi in "Registro (SynchronizationContext.Current);" e se non è "nullo", sapresti che hai un problema con "SynchronizationContext". – i3arnon

+0

'DoJob' vorrà sempre sincronizzarsi con il contesto di chiamata. Non importa quale contesto 'SomeIoOperation' utilizza. – Gusdor

risposta

8

Ti trovi esattamente in deadlock su SynchronizationContext. Basta usare WhenAll invece di WaitAll:

public async Task MethodExecutedByWorkerRoleInAnInfiniteLoop() 
{ 
    Log("Start"); 
    await Task.WhenAll(DoJob(), DoJob(), DoJob()); 
    Log("End"); 
} 

e tutto funzionerà.

+1

Questo metodo viene eseguito in un ciclo: il chiamante vorrà sapere quando il metodo è stato completato. IMO, questa revisione dovrebbe restituire 'Task'. – Gusdor

+0

Grazie. Ho appena dimenticato di cambiare nulla su Task. –

+0

Ma poi nel mio ciclo dovrò fare 'MethodExecutedByWorkerRoleInAnInfiniteLoop(). Wait()' - non causerà deadlock lì? Non esiste alcuna versione asincrona di 'RoleEntryPoint' in' Microsoft.WindowsAzure.ServiceRuntime', per quanto ne so, quindi non sarò in grado di attendere il mio 'MethodExecutedByWorkerRoleInAnInfiniteLoop' ovunque. –