【问题标题】:Immutable vs Concurrent Collections不可变集合与并发集合
【发布时间】:2021-08-27 14:58:36
【问题描述】:

在线程When immutable collections are preferable then concurrent 中指出,不可变集合可能会更慢,但它们可以节省内存。如果不可变集合的每次更改都会导致创建新对象,这怎么可能?

我知道并发集合是指一个对象,它使用同步原语。那么不可变集合如何比并发集合节省更多内存呢?

【问题讨论】:

  • 我不特别喜欢那个链接问题中的任何答案......主要的一点是,当访问一个不可变对象时,你可以确定它不会改变你.读取时不需要持有锁,不需要制作任何防御性副本等。读取并发集合时,如果在读取时集合发生更改,则需要确保一切安全,这意味着它需要在内部使用锁和其他技巧。当然有一个权衡。
  • 如果不可变集合的每次更改都会导致创建新对象,那怎么可能?”——这并不完全正确。不可变集合经过精心构造,因此如果您修改集合,您将获得一个新的、已更改的集合,但它会利用为原始集合分配的大部分数据。但是,是的,这是有代价的,这就是为什么这个问题谈到对经常读取但很少写入的数据使用不可变结构

标签: c# concurrency immutability immutable-collections


【解决方案1】:

不可变集合只能在非常特殊的情况下才能节省内存。主要是当您的应用程序的逻辑要求必须经常拍摄集合的快照时。例如,假设您的应用程序的一个工作流必须每隔几秒钟拍摄一次集合的快照并对其进行一些处理,而其他工作流会不断地改变集合。这就是不可变集合大放异彩的场景。对并发集合进行快照在所有方面(CPU/内存/争用)都是昂贵的,而对不可变集合进行快照基本上是免费的。根据定义,不可变集合具有快照语义。将不可变集合转换为快照所需的唯一事情是内存屏障,以便请求快照的线程可以确保它将看到存储在字段或变量中的最新且完全初始化的值。可以通过将字段声明为volatile 或通过使用Volatile.Read 方法读取变量来施加此内存屏障。示例:

var snapshot = Volatile.Read(ref _users);

附带说明,通过使用Interlocked 技术,也可以在不获取锁的情况下更新不可变集合。甚至还有一个可用的类 (ImmutableInterlocked) 大大简化了这些操作。示例:

ImmutableInterlocked.Update(ref _users, x => x.Add(user));

【讨论】:

    猜你喜欢
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 2019-10-13
    • 1970-01-01
    • 2012-01-19
    • 2011-03-11
    • 1970-01-01
    • 2012-01-07
    相关资源
    最近更新 更多