【问题标题】:Task.wait not working as I imaginedTask.wait 没有像我想象的那样工作
【发布时间】:2014-08-22 16:15:14
【问题描述】:

我正在尝试下载文件,等待文件完成下载,然后再读取文件。我有以下方法可以做到这一点:

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 会阻止方法的其余部分在任务完成之前执行?

【问题讨论】:

  • 两件事:你不需要在 StartDownload 中等待,你应该只返回 client.DownloadFileTaskAsync(new Uri(link), savePath);
  • 您不需要在 UI 线程中的任务上Wait。你需要 await 代替它。
  • @user,请看下面我的回答。我已经对其进行了测试,它可以正常工作并且不会阻塞 UI 线程。如果您有任何疑问,请发表评论:)

标签: c# multithreading task


【解决方案1】:

Task.Wait 将阻塞当前线程(在本例中为 UI 线程)并等待任务完成。在这种情况下,任务完成时出现错误,因此 Task.Wait 将抛出包裹在 AggregateException 中的错误。

正如其他人所说,您应该使用await 而不是Wait。此外,DownloadFileCompleted 没有意义,因为您使用的是DownloadFileTaskAsync(而不是DownloadFileAsync);并且StartNew 是不必要的,因为下载是异步的。

哦,让我们处理 WebClient 并确保我们的命名约定遵循 Task-based Asynchronous Pattern

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();
}

【讨论】:

    【解决方案2】:

    函数 startDownload 已经是异步的,所以它将启动任务并立即返回。您可以在调用 checkVersion() 之前使用 ContinueWith 确保任务完成。

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

    正如 Servy 指出的那样,另一种方法是在 Click 事件中使用 async/await。

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

    【讨论】:

    • 这当然会阻塞 UI 线程,冻结应用程序。
    • 根据您的第一个建议,我是否更改了 startDownload 中的任何内容?由于任务是异步的,它仍然会立即返回,所以它仍然会尝试打开文件,因为它仍在下载它。
    • @user2357446 它会立即返回,但在下载文件之前不会执行代码,使用此代码。
    • @user2357446 您可以删除 DownloadFileCompleted 的事件处理程序。
    【解决方案3】:

    您需要等待您的 Task.Factory.StartNew(...) 调用,这样它就不会阻塞 UI 线程。

    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.");
    }
    

    图片占位符由 Google 图片和其他一些网站提供。

    【讨论】:

    • 这与 OP 有相同的问题,因为您在完成启动任务时执行代码,而不是在您启动的任务完成时执行代码。
    • OP 应该将 checkVersion() 放在 DownloadFileCompleted 事件中,如果这是 OP 想要的。我一定是误会了。
    • 这是一种选择,是的。虽然不是最好的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-28
    • 1970-01-01
    • 2011-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多