处理取消令牌源的正确模式 [英] Correct pattern to dispose of cancellation token source

查看:26
本文介绍了处理取消令牌源的正确模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑这样一个场景,您需要完成一些异步工作,并且可以在即发即弃模式下运行它.这种异步工作能够侦听取消,因此您向它传递取消令牌以便能够取消它.

Consider a scenario where you have some asynchronous work to be done and you can run it in a fire and forget mode. This asynchronous work is able to listen for cancellation and so you pass it a cancellation token in order to being able to cancel it.

在给定的时刻,我们可以决定请求取消正在进行的活动,方法是使用我们从中获取取消令牌的取消令牌源对象.

At a given moment in time we can decide to request the cancellation of the ongoing activity, by using the cancellation token source object from which we have taken the cancellation token.

因为取消令牌源实现了IDisposable,所以只要我们完成它,我们就应该调用它的Dispose方法.这个问题的重点是确定何时您完成了给定的取消令牌源.

Because cancellation token source implements IDisposable, we should call its Dispose method as far as we are done with it. The point of this question is determining exactly when you are done with a given cancellation token source.

假设您决定通过调用取消令牌源上的Cancel 方法来取消正在进行的工作:在调用处置 ?

Let's suppose that you decide to cancel the ongoing work by calling the Cancel method on the cancellation token source: is it necessary to wait for the completion of the ongoing operation before calling Dispose ?

换句话说,我应该这样做:

Put in other words, should I do this way:

class Program 
{
  static void Main(string[] args) 
  {
    var cts = new CancellationTokenSource();
    var token = cts.Token;

    DoSomeAsyncWork(token); // starts the asynchronous work in a fire and forget manner

    // do some other stuff here 

    cts.Cancel();
    cts.Dispose(); // I call Dispose immediately after cancelling without waiting for the completion of ongoing work listening to the cancellation requests via the token

    // do some other stuff here not involving the cancellation token source because it's disposed
  }

  async static Task DoSomeAsyncWork(CancellationToken token) 
  {
     await Task.Delay(5000, token).ConfigureAwait(false);
  }
}

或者这样:

class Program 
{
  static async Task Main(string[] args) 
  {
    var cts = new CancellationTokenSource();
    var token = cts.Token;

    var task = DoSomeAsyncWork(token); // starts the asynchronous work in a fire and forget manner

    // do some other stuff here 

    cts.Cancel();

    try 
    {
      await task.ConfigureAwait(false);
    }
    catch(OperationCanceledException) 
    {
      // this exception is raised by design by the cancellation
    }
    catch (Exception) 
    {
      // an error has occurred in the asynchronous work before cancellation was requested
    }

    cts.Dispose(); // I call Dispose only when I'm sure that the ongoing work has completed

    // do some other stuff here not involving the cancellation token source because it's disposed
  }

  async static Task DoSomeAsyncWork(CancellationToken token) 
  {
     await Task.Delay(5000, token).ConfigureAwait(false);
  }
}

其他细节:我所指的代码是在 ASP.NET core 2.2 web 应用程序中编写的,这里我使用控制台应用程序场景只是为了简化我的示例.

Additional details: the code I'm referring to is written inside an ASP.NET core 2.2 web application, here I'm using a console application scenario just to simplify my example.

我在 stackoverflow 上发现了类似的问题,要求处理取消令牌源对象.一些答案表明,在某些情况下,并不真正需要处理这个对象.

I've found similar questions on stackoverflow asking for the need to dispose of cancellation token sources objects. Some of the answers suggest that in some scenario disposing of this object is not really needed.

我对整个 IDisposable 主题的方法是,我总是倾向于遵守类的公开契约,换句话说,如果一个对象声称是一次性的,我更喜欢始终调用 当我完成它时处理.我不喜欢根据类的实现细节来猜测是否真的需要调用 dispose 的想法,这些实现细节可能会在未来版本中以未记录的方式更改.

My approach to the whole IDisposable subject is that I always tend to adhere to the exposed contract of a class, put another way if an object claims to be disposable I prefer to always call Dispose when I'm done with it. I don't like the idea of guessing whether or not calling dispose is really required by depending on implementation details of the class that could change in a future release in an undocumented manner.

推荐答案

正确的做法是第二 - 在确定任务被取消后处理 CancellationTokenSource.CancellationToken 依赖于来自 CancellationTokenSource 的信息才能正常运行.虽然当前实现 CancellationToken 的编写方式即使在不抛出异常的情况下,如果创建它的 CTS 被释放,它仍然可以正常工作,但它可能无法正常运行或始终按预期运行.

The correct practice is second - you dispose of the CancellationTokenSource after you are sure the task is cancelled. CancellationToken relies on information from CancellationTokenSource to function properly. While the current implementation CancellationToken is written in such a way that is will still work even without throwing exceptions if the CTS it was created from is disposed, it may not behave properly or always as expected.

这篇关于处理取消令牌源的正确模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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