C#等待Task.Run不等待

时间:2019-06-04 13:07:38

标签: c# async-await

我有一些长期运行的后台计算任务

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()开始运行。

我在这里错了什么吗?

2 个答案:

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