我有一些代码调用下载文件的方法:
private async Task DownloadFile()
{
WebClient client = new WebClient();
var downloadTask =
Task.Run(
() =>
client.DownloadFile("http://www.worldofcats.com/bigkitty.zip",
"c:\\cats\\"
);
await downloadTask;
}
要调用此方法,我执行此操作:
var downloadTask = DownloadFile();
await downloadTask;
由于它是表单应用程序的一部分,因此在UI无响应的情况下下载时不会产生任何问题。唯一的问题是,DownloadFile方法没有超时,有时它可能出错或挂起,所以我需要暂停。
如果我使用Task.Wait(x);
,那么它会阻止UI线程。我想我可以使用await Task.WhenAny(downloadTask, () => Thread.Sleep(50000));
,但我不确定这是否是最佳方式。
所以我的问题是,我应该怎么做才能解决这个问题,如果它被强行终止,我怎样才能清理我的任务呢? (或者我必须担心吗?)
答案 0 :(得分:3)
您应该传递CancellationToken
:
private async Task DownloadFile()
{
WebClient client = new WebClient();
using(var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60))
{
var downloadTask =
Task.Run(
() =>
client.DownloadFile("http://www.worldofcats.com/bigkitty.zip",
"c:\\cats\\"),
cts.Token
);
await downloadTask;
}
}
现在当你await DownloadFile()
时,你可以将其包裹在try/catch
块中以捕获TaskCanceledException
(或OperationCanceledException
):
try
{
await DownloadFile();
}
catch(TaskCanceledException)
{
//Timeout!
}
正如评论中所注意到的那样,你无法取消一个不能取消注意的任务 - 不知怎的,我忘记了这一点(嘘!)。但不用担心,您可以使用DownloadFileTaskAsync
和CancelAsync
来解决这个问题,因此您甚至不需要取消令牌:
var downloadTask = client.DownloadFileTaskAsync("http://www.worldofcats.com/bigkitty.zip",
"c:\\cats\\");
var timerTask = Task.Delay(TimeSpan.FromSeconds(60));
await Task.WhenAny(downloadTask, timerTask);
client.CancelAsync(); // This does nothing if there's no operation in progress, as noted in documentation
答案 1 :(得分:-1)
检查结束:
private static async void Test()
{
var source = new CancellationTokenSource();
var watcher = Task.Delay(TimeSpan.FromSeconds(4), source.Token);
var downloadTask = Task.Factory.StartNew(() =>
{
//.. Simulating a long time task
Thread.Sleep(TimeSpan.FromSeconds(10));
},
source.Token);
await Task.Run(() => { Task.WaitAny(watcher, downloadTask); });
source.Cancel();
if (!downloadTask.IsCompleted)
Console.WriteLine("Time out!");
else
Console.WriteLine("Done");
}