Task.WhenAny节流效率

问题描述:

我最近阅读了一些使用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

在您调用“GetBitmapAsync”的同时,所有图像下载将同时并行执行。

循环只是检查哪些完成并将它们添加到面板。这样,您可以在到达图像后立即看到图像。

一旦任务结束,它不会影响其他任务的状态。

+0

这是因为任务将不会重新运行,因为任务只有在创建状态时才会运行。当它处于任何其他状态时,它不会运行,但返回它的当前状态正确吗? – Benji

+0

虽然您可以创建任务,但大多数情况下任务代表已经在运行的某些内容正在执行,因此一旦完成,您将无法再使用该任务执行它,您需要创建其他代表执行同样的操作。 – vtortola