2014-10-10 149 views
1

我有一个运行在从其他站点下载图像文件的asp.net web api中运行的代码。一次启动多个任务,然后在完成其中一个任务时启动另一个任务

这是我用来下载图像的代码。

 foreach (string file in images) 
     { 
      using (WebClient client = new WebClient()) 
      { 
       await client.DownloadFileTaskAsync(file, path + Path.GetFileName(file));      
      } 
     } 

我真正需要做的是立即开始10次下载。 (例如使用Task.Run ...或者其他方式),然后在最初开始的10逐个完成时逐个开始休息。

For EX。

启动10个任务

等到了10个任务完成一个

1次时完成,启动另一个任务

当其他1次完成,启动另一个任务等等

直到下载列表中的所有图像。

所以我的代码运行时最多有10周并发下载量(或小于10,如果没有更多的图像被下载。)

我使用.NET 4.5.2

你们可以指出我在正确的方向来实现这一目标吗?

+0

这不是说这回答你的问题,而是看看Hangfire http://hangfire.io/ - 看起来像是你的需求的完美契合 – 2014-10-10 11:19:04

+0

你可能需要启动10个任务,然后使用Task .WaitAny(taskList)' – artm 2014-10-10 11:22:42

回答

2

您可以使用SemaphoreSlim扼杀异步工作方式:

private readonly SemaphoreSlim _mutex = new SemaphoreSlim(10); 

... 

var downloads = images.Select(file => DownloadAsync(file)); 
await Task.WhenAll(downloads); 

... 

private async Task DownloadAsync(string file) 
{ 
    await _mutex.WaitAsync(); 
    try 
    { 
    using (WebClient client = new WebClient()) 
    { 
     await client.DownloadFileTaskAsync(file, path + Path.GetFileName(file));      
    } 
    } 
    finally 
    { 
    _mutex.Release(); 
    } 
} 

注:

  • 您可能需要调整System.Net.ServicePointManager.DefaultConnectionLimit
  • 您应该避免在ASP.NET上使用Task.Run。请参阅我的recent MSDN article on async ASP.NET了解更多详情。
+0

很好的答案。谢谢 :) – Amila 2014-10-11 17:50:20

0

我有点想大声这里,不知道这是否会工作,别人会希望它改善:

private void startFirst10Tasks() 
{ 
    List<Task> tasks = new List<Task>(); 
    //tasks.Add first 10 tasks 
    taskHandler(tasks); 
} 

private void taskHandler(List<Task> tasks) 
{ 
    Task.Factory.ContinueWhenAny(tasks, winner => 
     { 
      getNewTasks(tasks.Except(new List<Task>{winner})); 
     }); 
} 

private void getNewTasks(List<Task> tasks) 
{ 
    tasks.Add(
     Task.Factory.StartNew(() => 
     { 
      //Next DownloadFileTask 
     }) 
    ); 

    taskHandler(tasks); 
} 
相关问题