2016-02-15 108 views
2

我想圍繞如何在foreach循環中處理多個異步/等待調用。我有大約20,000行由foreach循環處理的數據。大約我的代碼是:在foreach循環迭代中多次異步/等待調用

foreach (var item in data) 
{ 
    if (ConditionA(item)) 
    { 
     if (ConditionAB(item)); 
     { 
      await CreateThingViaAPICall(item) 
     } 
     else 
     { 
      var result = await GetExistingRecord(item); 
      var result2 = await GetOtherExistingRecord(result); 
      var result3 = await GetOtherExistingRecord(result2); 
      //Do processing 
      ...   
      await CreateThingViaAPICall(); 
     } 
    } 
    ... and so on   
} 

我看過很多帖子說要使用異步在一個循環是建立任務列表,然後使用Task.WhenAll的最佳途徑。在我的情況下,我有任務相互依賴作爲每個迭代的一部分。在這種情況下,如何構建要執行的任務列表?

+0

你有什麼問題? –

+0

如果我沒有弄錯,在foreach中使用異步/等待的推薦方法是首先構建任務列表,然後調用Task.WhenAll。我的問題是,我有多個任務循環的每個迭代相互依賴。在這種情況下,我如何建立一個任務列表來等待? – Jacob

+0

我誤解了你的問題嗎?迭代中的每個項目是否取決於前一項的成功完成? –

回答

3

如果你打破個別項目的處理到一個單獨的(異步)方法最簡單的方法:

private async Task ProcessItemAsync(Item item) 
{ 
    if (ConditionA(item)) 
    { 
     if (ConditionAB(item)); 
     { 
      await CreateThingViaAPICall(item) 
     } 
     else 
     { 
      var result = await GetExistingRecord(item); 
      var result2 = await GetOtherExistingRecord(result); 
      var result3 = await GetOtherExistingRecord(result2); 
      //Do processing 
      ...   
      await CreateThingViaAPICall(); 
     } 
    } 
    ... and so on 
} 

然後處理您的收藏像這樣:

var tasks = data.Select(ProcessItemAsync); 
await Task.WhenAll(tasks); 

這有效地包裝了多個從屬將單個項目處理爲一個任務所需的任務,允許這些步驟順序發生,同時集合本身的項目同時處理。

由於成千上萬的項目中有10個,出於各種原因,您可能會發現需要限制同時運行的任務數量。看看這種情況下的TPL Dataflow。示例見here

+2

好吧,這是有道理的,並與@ jon-hanna的答案相結合更有意義。 – Jacob

+0

我理解你的問題的方式是可以同時處理項目A和項目B,但涉及處理單個項目的步驟必須按順序進行。這就是這種方法給你的。 –

1

如果我沒有弄錯,在foreach中使用異步/等待的推薦方法是首先創建一個任務列表,然後調用Task.WhenAll。

你有部分錯誤。

如果你有多個任務不依賴於對方,那麼在WhenAll中執行這些多任務通常是一個非常好的主意,這樣他們就可以一起調度,從而提供更好的吞吐量。

但是,如果每個任務取決於前一個的結果,那麼這種方法是不可行的。相反,你應該只是await他們在foreach

事實上,這對任何情況都可以正常工作,如果他們不需要,任務之間相互等待就不太理想。

foreach的能力await任務其實是最大的收穫一個async/await給了我們。大多數使用await的代碼可以很容易地重寫爲ContinueWith,如果不那麼優雅,但循環更復雜,並且只有通過檢查任務的結果才能找到實際的循環結尾,再次更復雜。

+0

因此,建議使用Task.WhenAll是一個性能相關的建議,而不是'壞的事情會發生,如果你這樣做'的建議? – Jacob

+1

是的。現在,當它適用時,它可能會產生很大的差異,所以當然可以採取這種方法。你甚至可以做一個混合;大塊中的每個塊都依賴於每個塊,但每個塊可以獨立。 –