2016-01-17 74 views
4

我有這樣的代碼:Task.StartNew Parallel.ForEach不等待

await Task.Factory.StartNew(
    () => Parallel.ForEach(
     urls, 
     new ParallelOptions { MaxDegreeOfParallelism = 2 }, 
     async url => 
     { 
      Uri uri = new Uri(url); 
      string filename = System.IO.Path.GetFileName(uri.LocalPath); 

      using (HttpClient client = new HttpClient()) 
      using (HttpResponseMessage response = await client.GetAsync(url)) 
      using (HttpContent content = response.Content) 
      { 
       // ... Read the string. 
       using (var fileStream = new FileStream(config.M_F_P + filename, FileMode.Create, FileAccess.Write)) 
       { 
        await content.CopyToAsync(fileStream); 
       } 
      } 
     })); 

MessageBox.Show("Completed"); 

它應該處理超過800個元素的列表,但它不等待下載和FILEWRITE是完了。 事實上,他開始下載和寫作,顯示消息,然後在後臺繼續下載... 我需要下載很多文件在並行和異步,但我必須等待所有的下載。這段代碼有什麼問題?

回答

4

Parallel.ForEach不適用於異步。它期望Action,但爲了等待異步方法,它需要得到一個Func<Task>

您可以使用TPL Dataflow的ActionBlock來代替使用異步構建。你給它一個委託(異步或不是)來執行每個項目。您可以配置塊的並行度(如果需要,還可以限制容量)。並且您將您的物品發佈到其中:

var block = new ActionBlock<string>(async url => 
{ 
    Uri uri = new Uri(url); 
    string filename = System.IO.Path.GetFileName(uri.LocalPath); 

    using (HttpClient client = new HttpClient()) 
    using (HttpResponseMessage response = await client.GetAsync(url)) 
    using (HttpContent content = response.Content) 
    { 
     // ... Read the string. 
     using (var fileStream = new FileStream(config.M_F_P + filename, FileMode.Create, FileAccess.Write)) 
     { 
      await content.CopyToAsync(fileStream); 
     } 
    } 
}, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 2 }); 

foreach (var url in urls) 
{ 
    block.Post(url); 
} 

block.Complete(); 
await block.Completion; 
// done 
+0

它說在此命名空間中不存在ActionBlock。如果我嘗試使用System.Threading.Tasks.Dataflow導入它,它說數據流不存在。我能做什麼? – giogiowefj

+0

@giogiowefj這是一個nuget,不是「傳統」.net框架的一部分。你可以在這裏得到它:https://www.nuget.org/packages/Microsoft.Tpl.Dataflow/ – i3arnon

+0

好吧,現在它運行,但它仍然不等待一切都要完成 – giogiowefj