C # — Дождитесь завершения загрузки нескольких файлов

#c# #async-await #task

#c# #асинхронное ожидание #задача

Вопрос:

У меня есть приложение, написанное на C #. В этом приложении мне нужно загрузить несколько файлов. Как только все файлы будут загружены, мне нужно сделать что-то еще. Пытаясь загрузить файлы одновременно, я написал следующее:

 private void DownloadFiles(string[] targets)
{
  var tasks = new List<Task>();
  foreach (var target in targets)
  {
    var task = DownloadFile(target);
    tasks.Add(task);
  }

  Task.WaitAll(tasks.ToArray());
}

private async Task DownloadFile(string target)
{
  using (var wc = new WebClient())
  {
    wc.DownloadProgressChanged  = (object sender, DownloadProgressChangedEventArgs e) => {
      Console.WriteLine(e.ProgressPercentage   "% downloaded.");
    }

    wc.DownloadFileCompleted  = (object sender, AsyncCompletedEventArgs e) => {
      Console.WriteLine(target   " was downloaded.");

      // TODO: Signal this "Task" is done
    }

    await wc.DownloadFileTaskAsync(target, localPath);
  }
}
  

Возможно, я запутался. На мой взгляд, я думаю, что мне нужно что-то сделать в DownloadFileCompleted . Или, может быть, достаточно await wc.DownloadFileTaskAsync строки.

Как мне загрузить несколько файлов одновременно, но дождаться, пока они все загрузятся, прежде чем продолжить?

Комментарии:

1. и что не так с вашим кодом?

2. @demo Я думаю, что его проблема в том, что он фактически не загружается параллельно (что он, очевидно, хочет сделать), потому что он ожидает DownloadFileTaskAsync в DownloadFile методе

Ответ №1:

Вы могли бы сделать следующее:

 private void DownloadFiles(string[] targets)
{
    var tasks = new List<Task>();
    using (var wc = new WebClient())
    {
        foreach (var target in targets)
        {
            var task = DownloadFile(wc, target);
            tasks.Add(task);
        }
        Task.WaitAll(tasks.ToArray());
    }
}


private Task DownloadFile(WebClient wc, string target)
{            
    wc.DownloadProgressChanged  = (object sender, DownloadProgressChangedEventArgs e) =>
    {
         Console.WriteLine(e.ProgressPercentage   "% downloaded.");
    };

    wc.DownloadFileCompleted  = (object sender, AsyncCompletedEventArgs e) =>
    {
         Console.WriteLine(target   " was downloaded.");
         // TODO: Signal this "Task" is done
    };

    return wc.DownloadFileTaskAsync(target, localPath);
 }
  

Я переместил WebClient в вызывающий метод, потому что вам придется держать его открытым до завершения всех загрузок (которые вы не знаете, когда они будут выполнены в вашем DownloadFile методе).

Кроме того, я удалил async из вашего объявления метода, потому что вам не нужно ждать чего-либо внутри метода.