2016-02-25 7 views
5

Sto cercando di asynchronize il mio codice originaleeseguire un task gruppo asincrone quando un certo ordine di esecuzione deve essere preservato

for(var item in items) 
{ 
    dbAccess.Save(item); 
} 

che funziona bene:

var tasks = new List<Task>(); 

    for(var item in items) 
    { 
     tasks.Add(dbAccess.SaveAsync(item)); 
    } 

    await Task.WhenAll(tasks); 

Tuttavia, ho bisogno di aggiungere un ulteriore clean-up call prima di salvare e oggetto ai miei DB:

var tasks = new List<Task>(); 

    for(var item in items) 
    { 
     tasks.Add(dbAccess.DeleteAsync(item.id)); 
     tasks.Add(dbAccess.SaveAsync(item)); 
    } 

    await Task.WhenAll(tasks); 

Questo codice di cui sopra non è corretto in quanto SaveAs ync non dovrebbe essere eseguito fino al completamento del DeleteAsync corrispondente. In altre parole, la cancellazione deve sempre andare prima del salvataggio per ogni articolo, ma l'ordine degli articoli non ha importanza.

Esiste un modo perfetto per farlo?

+1

Che ne dici di emettere tutte le eliminazioni prima, aspettandole, quindi emettendo tutti i salvataggi e quindi aspettando quelli? Altrimenti dovresti impacchettare ogni cancellazione + salvataggio in una singola attività. –

+0

Buon punto Lasse, ho semplificato il mio codice per lo scopo di questa domanda. Non riesco ad attuare il tuo suggerimento perché c'è un po 'di più che non sto mostrando. In realtà DeleteAsync restituisce qualcos'altro che deve essere passato a SaveAsync. – AstroSharp

+0

Quindi? Raggrupparli in un'attività che prima chiama deleteasync, quindi chiama saveasync in seguito? –

risposta

6

Creare un metodo async che esegue l'eliminazione, quindi il salvataggio, per un singolo elemento, e di eseguire tutte quelle operazioni composite su ogni elemento in parallelo:

var tasks = items.Select(async item => 
{ 
    await dbAccess.DeleteAsync(item.id); 
    await dbAccess.SaveAsync(item); 
}); 
await Task.WhenAll(tasks); 
2

È possibile utilizzare un Func<Task> per incapsulare le due chiamate asincrone in un unico Task come questo:

for(var item in items) 
{ 
    //We store the value of item in a local variable 
    //because it is not recommended to close over a loop variable 
    var my_item = item; 

    Func<Task> task_fact = async() => 
    { 
     await dbAccess.DeleteAsync(my_item.id); 
     await dbAccess.SaveAsync(my_item); 
    }; 

    tasks.Add(task_fact()); 
} 

Questo creerà un compito che chiama il metodo di eliminazione, in modo asincrono aspettare che si, e quindi chiama il salvataggio metodo e attendere in modo asincrono.

Si può fare la stessa cosa usando un metodo.

1

Come sull'utilizzo ContinueWith:

var tasks = new List<Task>(); 

for(var item in items) 
{ 
    var task = dbAccess.DeleteAsync(item.id) 
      .ContinueWith(antecedent => dbAccess.SaveAsync(item)) 
      .Unwrap(); 

    tasks.Add(task); 
} 

await Task.WhenAll(tasks); 
+0

È necessario scartare il risultato, poiché al momento non si è in attesa del completamento del salvataggio. È anche molto più complicato che usare 'await', e probabilmente non ha la semantica di gestione degli errori che vorresti. – Servy