使用异步任务取消任务 [英] Task cancellation with async task

查看:111
本文介绍了使用异步任务取消任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用此常见问题解答.这是我最初的想法:

I'm trying to make use of cancellation tokens as described in this FAQ. This was my initial thought:

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()
}

现在我对其进行了修改,结果如下:

Now I adapted it and this is the result:

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 .
  • 如何正确创建和销毁令牌以允许多次启动和取消操作?
  • 如何处理任务中的任务?控制台中显示完成",而任务(AsyncLoginTask)尚未完成.

推荐答案

我正在尝试使用本常见问题解答中所述的取消令牌.

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

该博文使用动态任务并行性( StartNew ContinueWith ).动态任务并行性是指您有许多需要执行CPU约束的操作并且在您已经处理完它们之前不知道有多少操作(即,您处理的每个任务都可以将零个或多个其他任务添加到同一个任务中)过程).

That blog post is using Dynamic Task Parallelism (StartNew and ContinueWith). Dynamic Task Parallelism is when you have a lot of CPU-bound operations to do and you don't know how many you have until you're already processing them (i.e., each one you process can add zero or more additional tasks to the same process).

在您的情况下,您只有一个异步操作.因此,该文章中的方法对于您的用例是完全错误的.您最初的想法更正确.

In your case, you have a single asynchronous operation. As such, the approach in that article is completely wrong for your use case. Your original thought was much more correct.

您想要做的更多:

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()
}

这篇关于使用异步任务取消任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆