如何在C#中使用TPL实现异步文件下载

How to achieve Async file download with TPL in C#

我有一个 windows 控制台客户端,它会休眠几分钟并在醒来时请求来自 Rest API 的新更新。该请求生成一个包含 json 数据的响应,其中包含一个对象列表,每个对象都包含 ID、描述、从 API 以 URL 发送到客户端的屏幕截图。控制台应用程序需要使用 json 响应,并且对于每个对象,它查找 URL 并尝试下载与列表中每个对象关联的相应图像。代码表示如下

foreach (var jobject in response)
{
    Console.WriteLine(jobject.id);
    Console.WriteLine(jobject.description);
    if (jobject.shotUrl != null)
    {
        WebClient webclient = new WebClient();
        webclient.DownloadFileAsync(new System.Uri(jobject.shotUrl), "F:\" + jobject.id + ".jpg");
    }
}

有时可能有大约 500 个 json 个对象,这意味着 500 张照片下载...再次意味着创建 500 个网络客户端。我觉得这不是个好主意。

我的问题是:如果我依赖 TPL,我能获得性能吗?怎么做?

使用HttpClient更容易并发,你可以为class声明一个私有的HttpClient:

System.Net.Http.HttpClient _client = new System.Net.Http.HttpClient();

然后你可以编写一个方法来下载文件并将它们保存到磁盘,如下所示:

 private async Task DownloadFile(string shortUrl, string destination)
 {
     using (var response = await _client.GetStreamAsync(shortUrl))
     using (var fileStream = File.Create(destination))
     {
         await response.CopyToAsync(fileStream);
         await fileStream.FlushAsync();
     }
 }

那么你可以这样使用它:

try
{
     await DownloadFile(jobject.shortUrl, "F:\" + jobject.id + ".jpg");
}
catch (Exception e)
{
     // Do appropriate exception handling
}

如果你想并行下载所有文件,你可以使用Task.WhenAll()

try
{
     var tasks = response.Select(j => DownloadFile(j.shortUrl, "F:\" + j.id + ".jpg"));
     await Task.WhenAll(tasks);
}
catch (Exception e)
{
     // Do appropriate exception handling
}