C# 任务,等等,没有我想象的那样工作
我正在尝试下载一个文件,等待该文件完成下载,然后读取该文件。我有以下方法来实现这一点:C# 任务,等等,没有我想象的那样工作,c#,multithreading,task,C#,Multithreading,Task,我正在尝试下载一个文件,等待该文件完成下载,然后读取该文件。我有以下方法来实现这一点: private async Task startDownload(string link, string savePath) { WebClient client = new WebClient(); client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_Do
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已经是异步的,因此它将启动任务并立即返回。在调用checkVersion()之前,可以使用ContinueWith确保任务已完成
正如Servy指出的,另一种选择是在Click事件中使用async/await
private async void checkUpdateButton_Click(object sender, EventArgs e)
{
await startDownload(versionLink, versionSaveTo);
checkVersion();
}
您需要等待
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 Images和其他一些网站提供。
任务。等待将阻止当前线程(在本例中为UI线程),并等待任务完成。在本例中,任务正在完成,但出现错误,因此task.Wait
将抛出包装在aggregateeexception
中的错误
正如其他人所指出的,您应该使用Wait
而不是Wait
。而且,DownloadFileCompleted
没有意义,因为您使用的是downloadfiletasksync
(而不是DownloadFileAsync
);由于下载是异步的,因此不需要启动新的StartNew
哦,让我们来处理WebClient
,并确保我们的命名约定遵循以下规则
两件事:在StartDownload
中不需要等待,只需返回client.DownloadFileTaskAsync(新Uri(链接),savePath)
您不需要在UI线程中等待任务。您需要等待它。@user,请查看下面我的答案。我已经对它进行了测试,它工作正常,不会阻塞UI线程。如果您有问题,请发表评论:)这当然会阻止UI线程,冻结应用程序。根据您的第一个建议,我是否要更改startDownload中的任何内容?它仍然会立即返回,因为任务是异步的,所以它仍然会在下载文件时尝试打开该文件。@user2357446它确实会立即返回,但在下载文件之前它不会执行代码,使用此代码。@user2357446您可以删除DownloadFileCompleted的事件处理程序。这与OP的问题相同,因为您在完成启动任务时执行代码,而不是在启动的任务完成时。OP应该在DownloadFileCompleted事件中放置checkVersion()
,如果那是OP想要的。我一定是误解了。这是一个选择,是的。但不是最好的。
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.");
}
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();
}