C# 如何使任务超时而不阻塞UI线程?
我有一些调用方法下载文件的代码:C# 如何使任务超时而不阻塞UI线程?,c#,task-parallel-library,C#,Task Parallel Library,我有一些调用方法下载文件的代码: private async Task DownloadFile() { WebClient client = new WebClient(); var downloadTask = Task.Run( () => client.DownloadFile("http://www.worldofcats.com/bigkitty.zip",
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;
由于它是表单应用程序的一部分,因此在用户界面无响应的情况下下载时不会引起任何问题。唯一的问题是,DownloadFile方法没有超时,有时可能会出错或挂起,所以我需要在其中设置一个超时
如果我使用Task.Wait(x)代码>然后它会阻止UI线程。我想我可以使用wait Task.WhenAny(downloadTask,()=>Thread.Sleep(50000))代码>但我不确定这是否是最好的方法
所以我的问题是,我应该做什么来解决这个问题,如果任务被强制终止,我该如何清理任务?(或者我必须担心吗?旧的解决方案,对于不知道取消的任务不可行
您应该传递一个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;
}
}
现在,当您等待下载文件()
时,可以将其包装在try/catch
块中,以捕获任务取消异常
(或):
[编辑]
正如在评论中所注意到的,你不能取消一个不知道取消的任务——不知怎么的,我忘记了(boo!)。但不用担心,您可以通过使用和来解决此问题,因此您甚至不需要取消令牌:
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
退房:
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");
}
检查有关睡眠与等待的一些信息。该令牌不能导致正在运行的任务停止。@usr True,不知何故我忘记了这一点(?),但正如编辑中所述,也有一个补救措施:)谢谢,正是它阻止了我使用取消令牌模式。Wait task.Run(()=>{task.WaitAny(watcher,downloadTask);})
请不要这样写代码。等待任务。wheny(watcher,downloadTask)
更好。
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");
}