2016-02-25 80 views
5

我想asynchronize我的原代碼運行一堆異步任務,當某一執行順序需要保留

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

的正常工作:

var tasks = new List<Task>(); 

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

    await Task.WhenAll(tasks); 

不過,我需要補充的額外的清理調用之前我保存和項目到我的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); 

上面這段代碼是因爲不正確另存直到相應的DeleteAsync完成後才能執行ync。換言之,刪除必須始終在每個項目的保存之前進行,但項目的順序無關緊要。

有沒有完美的方法來做到這一點?

+1

如何先發出所有的刪除,等待它們,然後發出所有的保存,然後等待那些?否則,你應該將每個刪除+保存打包成一個任務。 –

+0

好點Lasse,我爲了這個問題的目的簡化了我的代碼。我無法實現您的建議,因爲我沒有顯示更多信息。實際上,DeleteAsync會返回其他需要傳遞給SaveAsync的其他內容。 – AstroSharp

+0

那麼?將它們打包成一個首先調用deleteasync的任務,然後再調用saveasync? –

回答

6

創建async方法執行的刪除,則保存,對於一個單一的項目,並執行所有這些複合操作,在每個項目中並行:

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

可以使用Func<Task>封裝兩個異步調用到一個Task這樣的:

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()); 
} 

這將創建一個調用刪除方法,任務異步地等待它,然後調用保存方法並異步等待它。

您可以使用一種方法做同樣的事情。

1

如何使用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

您需要解開結果,因爲目前您並未等待保存完成。它比使用'await'更麻煩,並且可能沒有你想要的錯誤處理語義。 – Servy