我如何知道取消的异步任务是不是完成?

Posted

技术标签:

【中文标题】我如何知道取消的异步任务是不是完成?【英文标题】:How do I know if a cancelled async task is finished?我如何知道取消的异步任务是否完成? 【发布时间】:2021-03-29 06:50:07 【问题描述】:

最后在cmets后加

我有一个运行时间相当长的 Windows 窗体。所以我想我会让它异步。

因为有时操作者不想等到它完成,所以我给机会取消任务:

private CancellationTokenSource = new CancellationTokenSource();

private async Task<TResult> DoLongProcessingAsync(CancellationToken token)

     // do some long async processing; allow cancelling
     await Task.Delay(TimeSpan.FromSeconds(30), token);
     return new TResult() ...;


public async void ButtonStart_Clicked(object sender, ...)

    this.buttonStart.Enabled = false;
    this.ShowBusy(true);
    await this.DoLongProcessing(this.cancellationTokenSource.Token);
    this.ShowBusy(false);
    this.buttonStart.Enabled = true;

现在假设操作员在 DoLongProcessingAsync 完成之前关闭了表单。

private async void OnFormClosing(object sender, ...)

    bool closingAlloged = this.AskOperatorIfClosingAllowed();
    if (closingAllowed)
    
        this.cancellationTokenSource.Cancel();

        // TODO: await until DoLongProcessingAsync is finished
    

如何等待 LongProcessing 完成?

加法

有人说我应该等待任务。但是很可惜,Task 是 ButtonStart_Clicked 中的一个局部变量。我不确定是否应该将其作为类内的字段。

直到现在我还没有计划它,但只要它是一个局部变量,我可以通过单击几次来启动多个任务,并通过取消 CancellationTokenSource 将它们全部取消。

或者这真的是禁忌吗?

【问题讨论】:

如果你想知道任务何时完成,那么你await它,就像你在其他想知道操作何时完成的方法中所做的那样。 await 它并将其包装到一个 try-catch 中,如果等待的方法在内部调用传递的令牌上的 ThrowIfCancellationRequested 方法,您预计会出现 OperationCanceledException 我认为这可能很有趣:***.com/questions/16656523/…. Related: .NET Async in shutdown methods? 如果你能确保取消会立即发生,那就简单多了,这样你就可以Wait同步挂起的任务而不是awaiting它。跨度> 取消会在一秒左右结束,所以取消不会有问题。我想我必须让我的任务成为一个字段,并确保只有一个任务在运行。感觉很尴尬,任务仍然存在,即使它完成了。 【参考方案1】:

您已经在 (a) 等待 ButtonStart_Clicked 方法中的任务。 取消一个Task后,在OnFormClosing里面,可以catch一个TaskCanceledException

public async void ButtonStart_Clicked(object sender, ...)

    this.buttonStart.Enabled = false;
    this.ShowBusy(true);
    try
    
        await this.DoLongProcessing(this.cancellationTokenSource.Token);
    
    catch (TaskCanceledException ex)
    
        // handle task cancelled here
    
    catch (Exception ex)
    
        //handle other exceptions here
    
    finally
    
        this.ShowBusy(false);
        this.buttonStart.Enabled = true;
    

【讨论】:

但我在 OnFormClosing 中。我怎么知道 ButtonStart_Clicked 已经完成?我当然可以等待 SemaphoreSlim,但没有更聪明的方法吗?

以上是关于我如何知道取消的异步任务是不是完成?的主要内容,如果未能解决你的问题,请参考以下文章

在完成之前取消列表视图适配器的异步任务

如何从客户端取消异步任务

async和await异步编程资源汇总

Android取消多次调用的异步任务

在方法签名中使用异步时任务取消异常不会冒泡

如何在 C# Winforms 应用程序中取消执行长时间运行的异步任务