【问题标题】:Wait till all files are downloaded and wait till proccessing with those files are finished等到所有文件都下载完毕,然后等到这些文件的处理完成
【发布时间】:2021-02-17 14:27:28
【问题描述】:

我有一个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);
}

非常感谢!

【问题讨论】:

    标签: c# .net


    【解决方案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
        }
    }
    

    .AsParallel() 调用对下载文件后的 CPU 密集型工作很有帮助。否则你最好没有它。

    【讨论】:

    • 如果你想使用 await 你在方法上缺少一个 async 关键字
    • 非常感谢您的回答,它似乎工作得很好!但是,我只是想澄清一下,您的意思是说,如果我使用 GPU 绑定处理,我最好避免使用 .AsParallel()?
    • 不,如果您在下载后执行 GPU 或 CPU 操作,那么 AsParallel 应该有助于提高性能。只是说如果您所做的只是下载然后保存到磁盘或插入数据库或其他东西,它会增加开销。
    【解决方案2】:

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

    像这样:

    var downloadTasks = listOfFilesToDownload.Select(file =>
      {
        SaveFile(file, myModel);
      });
    
    var downloaded = await Task.WhenAll(customerTasks);
    

    等待所有文件保存完毕。

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-24
    • 1970-01-01
    • 1970-01-01
    • 2020-06-02
    • 2011-06-14
    • 2022-11-16
    • 2012-06-30
    相关资源
    最近更新 更多