为什么CancellationToken是一个结构体?

14

在 CancellationToken 的情况下,使用结构体而不是引用类型有意义吗?

我看到一种可能的缺点是,当我将它作为参数传递时,它将在整个方法链中被复制。

与此同时,由于它是结构体,它可能会更快地分配和释放。

如果我们想要使其不可变,则可以使用只读属性或私有设置器。

那么这背后的想法是什么?


3
虽然不是直接复制您的问题,但问题的被接受答案可能会提供一些见解。 - pstrjds
1
@Neir0:我仍然对你的反对意见感到困惑。结构体的大小与引用相同。你说,“一方面,我们只需要复制一个小的8字节引用,另一方面,我们必须复制整个8字节的结构体”。这没有任何意义。你的反对意见是什么? - Eric Lippert
1
@Eric Lippert 对不起,我没有检查CancellationToken的确切大小,它真的非常轻量级,我没有想到它只有一个字段。谢谢你的澄清。 - Neir0
@Neir0 通常情况下,如果没有非常好的理由,拥有一个比引用更大的结构体是一个错误。 - Servy
2
@Servy 我听说过一般建议至少使用16字节的值类型作为参数传递。 - Neir0
显示剩余6条评论
2个回答

18
有一篇文章介绍了.NET取消设计,值得一读,可以在这里查看。关于你的问题,在评论中问到以下内容:

只是出于兴趣,为什么CancellationToken是值类型?

提问者还提出了另一种使用单个共享实例作为引用类型的备选实现。
Mike Liddell的回答如下:

这肯定可以工作,并且在很大程度上是等效的(我们在早期原型设计中就是这样实现的),但是我们出于两个特定原因选择了当前设计:

- 每个CTS / Token只有一个类实例,因此减少GC压力。

- 我们将所有状态和大部分逻辑合并到CTS中。 分离的安排有点复杂。

我要注意的是,当前的值类型实现与引用类型完全相同大小,因此没有任何额外的复制开销。它还可以防止在用户代码中进行某些额外的模板代码空检查,特别是将token作为可选参数时。

9
在CancellationToken的情况下,使用struct而不是引用类型有意义吗?
是的。
我看到可能的缺点之一是,它将作为参数传递时在方法链中被复制到底部。
那不是缺点。取消标记的大小与引用相同。相对于传递引用,传递引用大小的结构体有何劣势?这个反对意见没有意义。请解释一下你为什么认为这是一个“缺点”。
同时,由于它是结构体,因此可能分配和释放更快。
没错,但实际上的胜利更可能是包装引用的引用大小结构体不会增加集合压力。 .NET框架中的许多设计和实现决策旨在确保框架代码不会增加太多的集合压力。
那么,这个想法是什么?
这是一个逻辑上是值的小型类型;它为什么不能是值类型呢?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接