2016-01-17 2 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>.

Вы можете использовать ActionBlock TPL Dataflow, который был создан вместо async. Вы даете ему делегат (асинхронный или нет) для выполнения каждого элемента. Вы настраиваете параллельность блока (и, при необходимости, ограниченную емкость). И вы публикуете свои позиции в нем:

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, то он говорит, что Dataflow не существует. Что я могу сделать? – giogiowefj

+0

@giogiowefj Это nuget, а не часть «традиционной» .net-структуры. Вы можете получить его здесь: https://www.nuget.org/packages/Microsoft.Tpl.Dataflow/ – i3arnon

+0

Теперь он работает, но он все еще не ждет завершения всего. – giogiowefj

Смежные вопросы