[英]Multiple async/await calls in a foreach loop iteration
我試圖把我的頭放在如何處理一個foreach循環中的多個異步/等待調用上。 我有大約20,000行數據由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。 就我而言,我的任務在每次迭代中都相互依賴。 在這種情況下,如何建立要執行的任務列表?
如果將單個項目的處理分成單獨的(異步)方法,這是最簡單的:
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);
這樣可以有效地將處理單個項目所需的多個從屬任務包裝到一個任務中,從而使這些步驟可以順序進行,而同時處理集合本身的項目。
擁有成千上萬個項目,由於各種原因,您可能會發現需要限制同時運行的任務數量。 看一下這種情況下的TPL數據流。 請參閱此處的示例。
如果我沒記錯的話,在foreach中使用異步/等待的推薦方法是先構建一個任務列表,然后調用Task.WhenAll。
您部分被誤解了。
如果您有多個相互不依賴的任務,那么將這些多個任務同時放在“ WhenAll
確實是一個很好的主意,以便可以一起調度它們,從而提高吞吐量。
但是,如果每個任務都取決於前一個任務的結果,則此方法不可行。 相反,您應該在foreach
await
它們。
確實,這在任何情況下都可以正常工作,讓任務在不需要時彼此等待只是次優的選擇。
在foreach
await
任務的能力實際上是async
/ await
給我們帶來的最大收益之一。 大部分使用await
代碼都可以很容易地重新編寫為使用ContinueWith
,即使不夠優雅,但是循環比較棘手,並且如果僅通過檢查任務本身的結果來發現循環的實際結尾,就再復雜一點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.