对于更新不依赖于先前值的不可变集合,是不是有任何理由更喜欢 Interlocked 而不是 volatile?

Posted

技术标签:

【中文标题】对于更新不依赖于先前值的不可变集合,是不是有任何理由更喜欢 Interlocked 而不是 volatile?【英文标题】:Is there any reason to prefer Interlocked over volatile for an Immutable Collection where updates do not depend on previous values?对于更新不依赖于先前值的不可变集合,是否有任何理由更喜欢 Interlocked 而不是 volatile? 【发布时间】:2021-06-08 02:07:32 【问题描述】:

我注意到在讨论不可变集合的问题中(例如What is the preferred method of updating a reference to an immutable object?) 建议使用Interlocked(或更好的ImmutableInterlocked)。原因似乎是 CAS,因为在大多数情况下,不可变集合会根据其先前的值进行更新。但是,假设我有一些包装了一个不可变集合的类,我希望它可以同时访问,并且新值不依赖于旧值,使用Interlocked 仍然是首选吗?换句话说,我有什么理由更喜欢这个:

public class Data 
   private ImmutableList<string> values;

   public ImmutableList<string> Read() 
       return Interlocked.CompareExchange(ref values, null, null);
   

   public void Write(IEnumerable<string> update) 
      //some arbitrary transformation that doesn't use values at all
      var newValues = update.Select(x => x + "-update").ToImmutableList(); 

      Interlocked.Exchange(ref values, newValues);
   

在此:

public class Data 
   private volatile ImmutableList<string> values;

   public ImmutableList<string> Read() 
       return values;
   

   public void Write(IEnumerable<string> update) 
      //some arbitrary transformation that doesn't use values at all
      var newValues = update.Select(x => x + "-update").ToImmutableList();

      values = newValues;
   


【问题讨论】:

【参考方案1】:

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

应该注意的是,不可变集合,尤其是ImmutableList&lt;T&gt; 的强大之处在于它们能够在每次更新时重用大部分内部状态。它们中的大多数被实现为二叉树,更新它们会导致替换树中的一些节点。如果您打算每次都更新整个集合,那么您会得到这种方法的所有缺点(开销、内存大小),而没有任何优点(内存可重用性)。

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

【讨论】:

感谢您的回答!为了跟进您的第二点——我在内部将其实现为易失性非不可变集合(例如常规List)并让Read()返回它的只读视图(如@ 987654332@)? @asdf 实际上你可以,特别是如果你希望成为这个 API 的唯一消费者。但语义不一样。不可变意味着没有人可以改变它,而只读意味着消费者不能改变它,但所有者可能可以。这是一个相关的问题:Why use ImmutableList over ReadOnlyCollection?

以上是关于对于更新不依赖于先前值的不可变集合,是不是有任何理由更喜欢 Interlocked 而不是 volatile?的主要内容,如果未能解决你的问题,请参考以下文章

使用Scala中的不可变值查找路径是不是存在于图形中

基于先前值更新Map中的值的惯用方法

是否可以交换集合中的两个元素?

可变数据类型与不可变数据类型

JDK中提供的不可变集合真的做到了不可变吗?

Python:集合操作总结