2016-11-26 82 views
1

我最近閱讀了一些使用TAP的文檔,特別是在較小標題「Task.WhenAny」下的this page。他們陳述4個主要目的爲Task.WhenAny:Task.WhenAny節流效率

  • 冗餘
  • 交錯
  • 節流
  • 早期救助

下方的交織(與間接地節流)小節他們有這樣的代碼

List<Task<Bitmap>> imageTasks = 
(from imageUrl in urls select GetBitmapAsync(imageUrl)).ToList(); 
while(imageTasks.Count > 0) 
{ 
    try 
    { 
     Task<Bitmap> imageTask = await Task.WhenAny(imageTasks); 
     imageTasks.Remove(imageTask); 

     Bitmap image = await imageTask; 
     panel.AddImage(image); 
    } 
    catch{} 
} 

這個代碼不會很低效嗎?我假設一旦Task.WhenAll的第一個任務完成後,將列表中的其他任務設置爲「RanToCompletion」或「Cancelled」或其他一些可以終止其他任務進度的狀態。所以,即使在這個例子中列表中只有2個任務可以下載圖片,1個圖片是2MB,另一個是4MB,但2MB圖片可能會先完成(而2MB將會被接收) 。然後它會從列表中刪除2MB並啓動循環。這似乎會再次啓動4MB下載,實質上已經浪費了已經取得的進展,正確嗎?

+0

爲什麼不寫一個代碼來測試你的假設?這通常是我理解一些概念的細節...... –

+0

'WhenAny'將具有集合中提供的完成任務之一的結果,它不會將所有任務設置爲取消或完成。一旦它執行圖像操作,它將重複該循環並獲得下一張要添加的圖像。另一方面,WhenAll'將返回一個只有在完成指定任務時纔會完成的任務。 – ColinM

+0

您可以隨時使用TPL DataFlow,其中包含** throttling **等功能。另外,TPL的流水線功能可以更好地服務於上面代碼的目的是想實現什麼 – MickyD

回答

1

在您調用「GetBitmapAsync」的同時,所有圖像下載將同時並行執行。

循環只是檢查哪些完成並將它們添加到面板。這樣,您可以在到達圖像後立即看到圖像。

一旦任務結束,它不會影響其他任務的狀態。

+0

這是因爲任務將不會重新運行,因爲任務只有在創建狀態時纔會運行。當它處於任何其他狀態時,它不會運行,但返回它的當前狀態正確嗎? – Benji

+0

雖然您可以創建任務,但大多數情況下任務代表已經在運行的某些內容正在執行,因此一旦完成,您將無法再使用該任務執行它,您需要創建其他代表執行同樣的操作。 – vtortola