C# 对于更新不依赖于以前的值的不可变集合,是否有任何理由选择联锁而不是volatile?

C# 对于更新不依赖于以前的值的不可变集合,是否有任何理由选择联锁而不是volatile?,c#,concurrency,immutability,volatile,interlocked,C#,Concurrency,Immutability,Volatile,Interlocked,我注意到在讨论不可变集合的问题中(例如) 建议使用联锁(或更好的不可变联锁)。这样做的原因似乎是因为CAS,因为在大多数情况下,不可变集合是基于其以前的值进行更新的。然而,假设我有一个类包装了一个不可变的集合,我希望这个集合可以被并发访问,并且新值不依赖于旧值,那么使用Interlocked仍然是首选吗?换言之,我有什么理由喜欢这样: 公共类数据{ 私有不可变列表值; 公共不可变列表读取(){ 返回Interlocated.CompareExchange(参考值,null,null); } 公共

我注意到在讨论不可变集合的问题中(例如) 建议使用
联锁
(或更好的
不可变联锁
)。这样做的原因似乎是因为CAS,因为在大多数情况下,不可变集合是基于其以前的值进行更新的。然而,假设我有一个类包装了一个不可变的集合,我希望这个集合可以被并发访问,并且新值不依赖于旧值,那么使用
Interlocked
仍然是首选吗?换言之,我有什么理由喜欢这样:

公共类数据{
私有不可变列表值;
公共不可变列表读取(){
返回Interlocated.CompareExchange(参考值,null,null);
}
公共无效写入(IEnumerable更新){
//一些根本不使用值的任意转换
var newValues=update.Select(x=>x+“-update”).ToImmutableList();
联锁交换(参考值、新值);
}
}
在这方面:

公共类数据{
私有易失性不可变列表值;
公共不可变列表读取(){
返回值;
}
公共无效写入(IEnumerable更新){
//一些根本不使用值的任意转换
var newValues=update.Select(x=>x+“-update”).ToImmutableList();
值=新值;
}
}

不,没有理由。将
字段标记为
volatile
足以确保所有线程都能看到存储在此字段中的最新值

但应该注意的是,不可变集合的威力,尤其是不可变集合的威力,取决于它们在每次更新时重用其大部分内部状态的能力。如果将它们实现为二叉树,则大多数情况下,更新它们会导致替换树中的一些节点。如果每次都要更新整个集合,那么这种方法会有所有的缺点(开销、内存大小),而没有任何优点(内存可重用性)


此规则的例外是结构,它在内部作为简单数组实现。它不提供可重用性,但它的性能非常好,因此它似乎非常适合您的情况。要克服它是值类型这一事实,您可以将其存储在类型为的字段中。

谢谢您的回答!继续你的第二点——我是否也可以在内部将其实现为一个不可变的集合(例如,常规的
列表
),并让
Read()
返回它的只读视图(如
IReadOnlyCollection
)?@asdf实际上你可以,特别是如果您希望成为此API的唯一消费者。但是语义是不一样的。不可变意味着没有人可以更改它,而只读意味着消费者不能更改它,但所有者可能可以。以下是一个相关问题: