Task.StartNew Parallel.ForEach doesn't await

本文关键字:await doesn StartNew Parallel ForEach Task | 更新日期: 2023-09-27 18:30:41

我有这个代码:

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个元素的列表,但它不会等待下载和文件写入完成。事实上,他开始下载和写作,显示消息,然后在后台继续下载......我需要并行和异步下载大量文件,但我必须等待所有文件下载。这段代码有什么问题?

Task.StartNew Parallel.ForEach doesn't await

Parallel.ForEach不适用于

异步。它需要一个Action但为了等待异步方法,它需要获得一个Func<Task>

您可以使用 TPL 数据流的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