【问题标题】: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;
   }

}

【问题讨论】:

    标签: c# concurrency immutability volatile interlocked


    【解决方案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?
    猜你喜欢
    • 2011-03-18
    • 2011-06-18
    • 1970-01-01
    • 2011-11-03
    • 1970-01-01
    • 2018-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多