2013-10-09 81 views
12

如何構建下面的代碼以便調用異步方法?如何正確使用異步方法編寫Parallel.For

Parallel.For(0, elevations.Count(), delegate(int i) 
{ 
    allSheets.AddRange(await BuildSheetsAsync(userID, elevations[i], includeLabels)); 
}); 
+0

[Parallel.ForEach中嵌套等待]的可能的重複(https://stackoverflow.com/questions/11564506/nesting-await-in-parallel-foreach) –

回答

22

Parallel.For()async方法很好地工作。如果您不需要限制並行度(即您可以同時執行所有任務),則可以簡單地啓動所有的Task,然後等待它們完成:

var tasks = Enumerable.Range(0, elevations.Count()) 
    .Select(i => BuildSheetsAsync(userID, elevations[i], includeLabels)); 
List<Bitmap> allSheets = (await Task.WhenAll(tasks)).SelectMany(x => x).ToList(); 
+0

我無法添加它要求IEnnumerable的List 的集合。我如何做到這一點? var task = Enumerable.Range(0,elevations.Length).Select(i => BuildSheetsAsync(userID,elevation [i],includeLabels)); 列表 allSheets =新列表(); allSheets.AddRange(等待Task.WhenAll(任務));發生錯誤時,我allSheets.AddRange(等待Task.WhenAll(任務)); –

+0

@ AlumCloud.Com啊,我沒有注意到'BuildSheetsAsync()'已經返回一個集合。如果你想從一個集合集合中創建一個集合,你可以使用'SelectMany()'。並且要從'IEnumerable'集合中創建一個列表,使用'ToList()'。 – svick

+0

賓果!非常感謝。 –

4

我建議你看看這個問題,我問前幾天,結束行動回答我,基本上我一直在尋找一個並行和異步的ForEach方法

該方法使用SemaphoreSlim來並行處理事物,它接受異步方法作爲輸入操作。

您可能還想看看我在答覆結束時提供的兩個鏈接,它們對於實現此類行爲非常有幫助,而且它們還包含使用Partitioner代替的另一種方法。

就我個人而言,我不喜歡Parallel.For,因爲它是一個同步調用,如我在給出的鏈接中所解釋的;我想這一切「異步」 :-)

這就是:Asynchronously and parallelly downloading files

+1

+1,除了'SemaphoreSlim'顯然不是必需的OP的情況。我也可以建議在代碼中使用具有超時的'CancellationTokenSource'而不是'Timer'對象。 – Noseratio

2

調用裏面Parallel.For您的異步方法最簡單的方法是下一個:

Parallel.For(0, elevations.Count(), async i => 
{ 
    allSheets.AddRange(await BuildSheetsAsync(userID, elevations[i], includeLabels)); 
}); 

==============

MarioDS提到的評論絕對正確的,在這種情況下你可能有沒有觀察到的例外。這絕對是非常重要的事情,您應該始終考慮與異步代表達成協議。

在這種情況下,如果您認爲您會有例外情況,則可以在代表內使用try/catch塊。或者在某些情況下,如果您的情況良好,您可以訂閱TaskScheduler.UnobservedTaskException活動。

+1

這會導致錯誤。異步委託返回「Task」,而Parallel構造不會等待該任務。這意味着異常是不可見的,你不能確定在「並行」之後。因爲調用已經證明所有的工作都已經完成了(你也不能輕易驗證)。 – MarioDS

相關問題