我有一些长期运行的后台计算任务
private async void StartButton_onClick(object sender, RoutedEventArgs e)
{
cts = new CancellationTokenSource();
var task = Task.Run(() => Calculate(cts.Token));
tasks.Add(task);
await task;
tasks.Remove(task);
cts = null;
}
用户单击Cancel
按钮可以取消任务,而当用户调用其他活动时可以自动取消任务,例如,按Change
按钮打开对话框以更改计算参数。
为了避免两次为两次写入取消代码,我将其移至单独的方法
public async void CancelAsync()
{
if (cts != null && !cts.IsCancellationRequested)
{
cts.Cancel();
await Task.WhenAll(tasks);
}
}
并从按钮单击事件中调用它
private async void CancelButton_onClick(object sender, RoutedEventArgs e)
{
await Task.Run(() => CancelAsync());
}
private async void ChangeButton_onClick(object sender, RoutedEventArgs e)
{
await Task.Run(() => CancelAsync());
OpenDialog();
}
问题在于OpenDialog()
方法被称为之前 CancelAsync()
开始运行。
我在这里错了什么吗?
答案 0 :(得分:3)
由于您正在从既非异步也未等待的lambda调用CancelAsync(),因此该lambda将在CancelAsync()
方法返回之前完成。为了使其按预期工作,可以使用
public async Task CancelAsync()
{
if (cts != null && !cts.IsCancellationRequested)
{
cts.Cancel();
await Task.WhenAll(tasks);
}
}
await CancelAsync();
答案 1 :(得分:1)
问题是使用Task.Run
,它的意思是在线程池上运行一些同步代码,并让您等待其结果。但是,您正在将异步代码传递给Task.Run
,就好像它是同步代码一样,因此Task.Run认为工作是在CancelAsync()返回任务后立即完成的,而不是在任务完成时完成。
尝试以下方法:
private async void ChangeButton_onClick(object sender, RoutedEventArgs e)
{
await CancelAsync();
OpenDialog();
}