Task.wait не работает, как я себе представлял

1

Я пытаюсь загрузить файл, дождитесь окончания загрузки файла, а затем прочитайте файл после этого. У меня есть следующие методы:

private async Task startDownload(string link, string savePath)
{      
        WebClient client = new WebClient();
        client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
        client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
        await client.DownloadFileTaskAsync(new Uri(link), savePath);              
}

private void checkUpdateButton_Click(object sender, EventArgs e)
{           
    Task task = Task.Factory.StartNew(() => startDownload(versionLink, versionSaveTo));
    task.Wait();

    if (task.IsCompleted)
    {
        checkVersion();
    }
}

Метод checkVersion() считывает загруженный файл. Это бросает IOException говоря, что файл используется кем-то другим и не может быть прочитан. Я думал, что с task.Wait будет препятствовать выполнению остальной части метода до завершения задачи?

  • 0
    Две вещи: вам не нужно ждать в StartDownload , вы должны просто вернуть client.DownloadFileTaskAsync(new Uri(link), savePath);
  • 3
    Вам не нужно Wait выполнения задачи в потоке пользовательского интерфейса. Вы должны await этого вместо этого.
Показать ещё 1 комментарий
Теги:
multithreading
task

3 ответа

1

Task.Wait заблокирует текущий поток (в данном случае поток пользовательского интерфейса) и дождитесь завершения задачи. В этом случае задача завершается с ошибкой, поэтому Task.Wait будет Task.Wait эту ошибку, заключенную в Task.Wait AggregateException.

Как отмечали другие, вы должны использовать await вместо Wait. Кроме того, DownloadFileCompleted не имеет смысла, поскольку вы используете DownloadFileTaskAsync (а не DownloadFileAsync); и StartNew так как загрузка является асинхронной.

О, и пусть утилита WebClient и убедитесь, что наше соглашение об именах следует Асинхронному шаблону на основе задач.

private async Task startDownloadAsync(string link, string savePath)
{      
  using (var client = new WebClient())
  {
    client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
    await client.DownloadFileTaskAsync(new Uri(link), savePath);              
  }
}

private async void checkUpdateButton_Click(object sender, EventArgs e)
{           
  await startDownloadAsync(versionLink, versionSaveTo);
  checkVersion();
}
0

Функция startDownload уже асинхронна, поэтому она начнет задачу и сразу вернется. Вы можете использовать ContinueWith для обеспечения выполнения задачи перед вызовом функции checkVersion().

    private void checkUpdateButton_Click(object sender, EventArgs e)
    {
        var task = startDownload(versionLink, versionSaveTo);
        task.ContinueWith((x) => checkVersion());
    }

Альтернатива, как указывает Servy, заключается в использовании async/wait в событии Click.

    private async void checkUpdateButton_Click(object sender, EventArgs e)
    {
        await startDownload(versionLink, versionSaveTo);
        checkVersion();
    }
  • 0
    Который, конечно, заблокирует поток пользовательского интерфейса, замораживая приложение.
  • 0
    С вашим первым предложением я что-то меняю в startDownload? Он по-прежнему немедленно возвращается, поскольку задача асинхронная, поэтому он все еще пытается открыть файл, пока загружает его.
Показать ещё 2 комментария
-1

Вам нужно будет дождаться Task.Factory.StartNew(...), таким образом, он не блокирует поток пользовательского интерфейса.

private async void button1_Click(object sender, EventArgs e)
{
    Task task = await Task.Factory.StartNew(() => startDownload("http://www.zwaldtransport.com/images/placeholders/placeholder1.jpg", "" + "sd.jpg"));
}

private async Task startDownload(string link, string savePath)
{
    WebClient client = new WebClient();
    client.DownloadProgressChanged += Client_DownloadProgressChanged;
    client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
    await client.DownloadFileTaskAsync(new Uri(link), savePath);
}

private void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
            checkVersion();
    Console.WriteLine("Done, unless error or cancelled.");
}

private void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    Console.WriteLine("Progress changed.");
}

Image placeholder courtesy Google Images и другой сайт.

  • 0
    Это та же проблема, что и у OP, в том, что вы выполняете код, когда завершаете запуск задачи, а не когда завершается задача, которую вы запускаете.
  • 0
    OP должен поместить checkVersion() в событие DownloadFileCompleted, если этого хочет OP. Должно быть, я неправильно понял.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню