为什么是的CancellationToken分开CancellationTokenSource?(W

2019-07-18 00:15发布

我在寻找为什么.NET的CancellationToken结构是除了CancellationTokenSource类推出的一个理由。 我理解的API是如何被使用的,但也想了解为什么它就是这样设计的。

即,为什么我们有:

var cts = new CancellationTokenSource();
SomeCancellableOperation(cts.Token);

...
public void SomeCancellableOperation(CancellationToken token) {
    ...
    token.ThrowIfCancellationRequested();
    ...
}

而不是直接通过CancellationTokenSource周围像:

var cts = new CancellationTokenSource();
SomeCancellableOperation(cts);

...
public void SomeCancellableOperation(CancellationTokenSource cts) {
    ...
    cts.ThrowIfCancellationRequested();
    ...
}

这是基于一个事实,即取消国家抽查不是围绕传送令牌更频繁地发生一个性能优化?

这样CancellationTokenSource可以跟踪和更新CancellationTokens,并为每个令牌取消检查是本地字段访问?

由于没有锁定挥发性布尔足够在这两种情况下,我还是不能明白为什么会更快。

谢谢!

Answer 1:

我参与了设计和实现这些类的。

简短的回答是“关注点分离”。 这是千真万确的,有不同的实施策略和一些至少对于类型系统和最初的学习更简单。 然而,CTS和CT打算用在许多情况下(如深图书馆的书库,并行计算,异步等),因此在设计上有许多复杂的用例记在心里。 这是旨在鼓励成功的模式并阻止反模式在不牺牲性能的设计。

如果门是开着的行为不端的API,然后取消设计的有效性可能迅速被侵蚀。



Answer 2:

I had the exact same question and I wanted to understand the rationale behind this design.

The accepted answer got the rationale exactly right. Here's the confirmation from the team who designed this feature (emphasis mine):

Two new types form the basis of the framework: A CancellationToken is a struct that represents a ‘potential request for cancellation’. This struct is passed into method calls as a parameter and the method can poll on it or register a callback to be fired when cancellation is requested. A CancellationTokenSource is a class that provides the mechanism for initiating a cancellation request and it has a Token property for obtaining an associated token. It would have been natural to combine these two classes into one, but this design allows the two key operations (initiating a cancellation request vs. observing and responding to cancellation) to be cleanly separated. In particular, methods that take only a CancellationToken can observe a cancellation request but cannot initiate one.

Link: .NET 4 Cancellation Framework

In my opinion, the fact that CancellationToken can only observe the state and not change it, is extremely critical. You can hand out the token like a candy and never worry that someone else, other than you, will Cancel it. It protects you from hostile third party code. Yes, the chances are slim, but I personally like that guarantee.

I also feel that it makes the API cleaner and avoids accidental mistake and promotes better component design.

Let's look at public API for both of these classes.

If you were to combine them, when writing LongRunningFunction, I will see methods like those multiple overloads of 'Cancel' which I should not be using. Personally, I hate to see Dispose method as well.

I think the current class design follows 'pit of success' philosophy, it guides developers to create better components which can handle Task cancellation and then instrument them together in numerous way to create complicated workflows.

Let me ask you a question, have you wondered what is the purpose of token.Register? It didn't make sense to me. And then I read Cancellation in Managed Threads and everything became crystal clear.

I believe that the Cancellation Framework Design in TPL is absolutely top notch.



Answer 3:

它们是独立的不是技术原因,而是语义的。 如果你看一下执行CancellationToken ILSpy下,你会发现它只是周围的包装CancellationTokenSource (因此没有什么不同性能方面比通过围绕基准)。

它们提供这种分离的功能,使事情变得更加可以预测的:当你通过一个方法CancellationToken ,你知道你仍然可以取消它唯一的一个。 当然,该方法仍可以抛出TaskCancelledException ,但CancellationToken本身-以及任何其他方法引用同样的道理-仍将是安全的。



Answer 4:

该的CancellationToken是一个结构这么多的副本可能会因为其传递的方法存在。

该CancellationTokenSource设置呼叫源上取消时,令牌的所有副本的状态。 看到这个MSDN页

究其原因,设计可能只是一个关注点分离的物质和结构的速度。



Answer 5:

该CancellationTokenSource是“东西”发出的取消,无论出于何种原因。 它需要一种方式来“调度”该取消所有的CancellationToken的已经发行了。 这是怎么了,例如,ASP.NET可以取消操作时,请求被中止。 每个请求有一个CTSource转发该取消它发出的所有令牌。

这个伟大的单元测试BTW - 创建自己的取消标记源,获得令牌,呼吁soource取消,并通过令牌代码是必须处理的取消。



Answer 6:

我的“理论”是的CancellationToken的作用是提供一个线程安全的包装,以避免冲突

如果只有一个类,因此唯一的实例将与参考副本中使用,并且你有很多的线程登记注销例如处理的,这个类应该使用一些锁,降低了性能管理并发。

而用的CancellationToken结构必须为每个线程所以没有争每一个回调队列的副本。

这是纯粹的投机,我可能是完全错误的和/或有可能是此设计其他充分的理由。

这是唯一确定的事情是,至少有一个很好的理由,这是一种耻辱,这种决定是不是多有记载,因为它使用技术时是一个非常宝贵的见解。



文章来源: Why CancellationToken is separate from CancellationTokenSource?