2014-10-10 233 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); 
} 
相關問題