等待所有文件下载完毕,并等待这些文件的处理完成

时间:2021-02-17 14:27:28

标签: c# .net

我有一个listOfFilesToDownload。我想并行下载列表中的所有文件

.........

Parallel.ForEach(listOfFilesToDownload, (file) =>
{
    SaveFile(file, myModel);
});

private static void SaveFile(string file, MyType myModel)
{
    filePath = "...";
    try
    {
        using (WebClient webClient = new WebClient())
        { 
            webClient.DownloadFileTaskAsync(file, filePath)                      
        }
        //some time consuming proccess with downloaded file 
    }
    catch (Exception ex)
    {   
    }
}

SaveFile方法中我下载了文件,然后我想等到它被下载,然后对这个文件做一些处理,等到这个处理完成。完整的迭代必须是 - 下载文件并处理它 所以,问题是:

  1. 如何以最佳方式等待文件下载,以便没有被阻止并具有最大性能(我的意思是如果我只使用 DownloadFile,它将阻塞线程直到文件下载,我认为这不太好)
  2. 如何确保文件被下载,然后才开始处理它(因为如果我开始处理不存在的文件或未完全下载的文件,我将有错误或错误的数据)
  3. 如何确保文件处理完成(因为我尝试使用 webClient.DownloadFileCompleted 事件并在那里处理文件,但我没有设法确保处理完成,示例如下)

复杂的问题是如何等待文件异步下载并等到它被处理

            using (WebClient webClient = new WebClient())
            {
                webClient.DownloadFileCompleted += DownloadFileCompleted(filePath, myModel);
                webClient.DownloadFileTaskAsync(file, filePath);
            }

DownloadFileCompleted 返回 AsyncCompletedEventHandler:

public static AsyncCompletedEventHandler DownloadFileCompleted(string filePath, MyType myModel)
{
    Action<object, AsyncCompletedEventArgs> action = (sender, e) =>
    {
    if (e.Error != null)
        return;
    //some time consuming proccess with downloaded file 
    };
    return new AsyncCompletedEventHandler(action);
}

非常感谢!

2 个答案:

答案 0 :(得分:1)

你考虑过 Task.WhenAll 吗?类似的东西:

var tasks = listOfFilesToDownload
    .AsParallel()
    .Select(f => SaveFile(f, myModel))
    .ToList();
await Task.WhenAll(tasks);

private static async Task SaveFile(string file, MyType myModel)
{
    filePath = "...";
    using (WebClient webClient = new WebClient())
    { 
        await webClient.DownloadFileTaskAsync(file, filePath);
        // process downloaded file
    }
}

如果您在下载文件后正在进行 CPU 密集型工作,则 .AsParallel() 调用会很有帮助。否则你最好没有它。

答案 1 :(得分:0)

this answer 所述,Parallel.ForEach() 背后的整个想法是您有一组线程,每个线程处理集合的一部分,因此您不能等待保存部分完成。您可以做的是使用 Dataflow 而不是 Parallel.ForEach,后者很好地支持异步任务。

像这样:

var downloadTasks = listOfFilesToDownload.Select(file =>
  {
    SaveFile(file, myModel);
  });

var downloaded = await Task.WhenAll(customerTasks);

等待所有文件保存完毕。

同一问题的其他答案可能对您有用。

相关问题