c# - 使用异步任务取消任务

标签 c# asynchronous async-await task cancellation

我正在尝试使用 this FAQ 中所述的取消 token 。这是我最初的想法:

private async void OnLoginButtonClicked(object sender, EventArgs e)
{
    if (this.cancelToken == null)
    {
        this.cancelToken = new CancellationTokenSource();
    }

    try
    {
        bool loginSuccess = await AsyncLoginTask(this.cancelToken.Token);

        if (loginSuccess)
        {
            // Show main page
        }
    }
    catch (OperationCanceledException ex)
    {
        System.Diagnostics.Debug.WriteLine(ex.Message);
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex.Message);
    }
    finally
    {
        this.cancelToken = null;
    }
}

private async Task<bool> AsyncLoginTask(CancellationToken cancellationToken = default(CancellationToken))
{
    // Pass the token to HttpClient()
}

现在我对其进行了修改,这就是结果:

private async void OnLoginButtonClicked(object sender, EventArgs e)
{
    this.cancelToken?.Dispose();
    this.cancelToken = new CancellationTokenSource();

    try
    {
        var ui = TaskScheduler.FromCurrentSynchronizationContext();
        var loginTask = Task.Factory.StartNew(async () =>
        {
            bool loginSuccess = await AsyncLoginTask(this.cancelToken.Token);
        }, this.cancelToken.Token);

        var displayResults = loginTask.ContinueWith(resultTask =>
                            {
                                // How do I know if the login was successful?
                                // Because AsyncLoginTask() returns bool.
                                System.Diagnostics.Debug.WriteLine("done");
                            },
                             CancellationToken.None,
                             TaskContinuationOptions.OnlyOnRanToCompletion,
                             ui);

        var displayCancelledTasks = loginTask.ContinueWith(resultTask =>
                                    {
                                        System.Diagnostics.Debug.WriteLine("canceled");
                                    },
                                   CancellationToken.None,
                                   TaskContinuationOptions.OnlyOnCanceled, ui);
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex.Message);
    }
}

问题:

  • 我如何知道登录是否成功?因为 AsyncLoginTask() 返回 bool
  • 如何正确创建和销毁 token 以允许多次启动和取消操作?
  • 如何处理任务中的任务?控制台中显示“done”,但任务 (AsyncLoginTask) 尚未完成。

最佳答案

I'm trying to make use of cancellation tokens as described in this FAQ.

该博客文章使用动态任务并行性(StartNewContinueWith)。动态任务并行是指您有大量 CPU 密集型操作要做,并且在处理完这些操作之前您不知道有多少操作(即,您处理的每个操作都可以向同一操作添加零个或多个附加任务)过程)。

就您而言,您有一个异步操作。因此,该文章中的方法对于您的用例来说是完全错误的。你原来的想法更正确。

你想要这样做:

private async void OnLoginButtonClicked(object sender, EventArgs e)
{
  // Cancel the previous attempt (if any) and start a new one.
  this.cts?.Cancel();
  this.cts = new CancellationTokenSource();

  try
  {
    bool loginSuccess = await AsyncLoginTask(this.cts.Token);
    // Resolve race condition where user cancels just as it completed.
    this.cts.Token.ThrowIfCancellationRequested();
    if (loginSuccess)
    {
      // Show main page
    }
  }
  catch (OperationCanceledException ex)
  {
    System.Diagnostics.Debug.WriteLine(ex.Message);
  }
  catch (Exception ex)
  {
    System.Diagnostics.Debug.WriteLine(ex.Message);
  }
}

private async Task<bool> AsyncLoginTask(CancellationToken cancellationToken = default(CancellationToken))
{
  // Pass the token to HttpClient()
}

关于c# - 使用异步任务取消任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44260010/

相关文章:

c# - 从异步方法返回IAsyncEnumerable

C# 位图不按原样保存

c# - 关于构建强类型类来管理 asp.net mvc 的 URL 的想法

c# - 三重 DES 加密

java - Spring 3.x - @Async 方法不被任务执行器同时调用

asynchronous - 有没有办法等待返回Result <T,E>而不是T?

Javascript for循环,等待函数回调

c# - 如何将 ComObject 转换为 ENVDTE.Project?

c# - 结果类型未知的任务

node.js - 为什么这些 promise 的拒绝是全局性的?