50万奖金+官方证书,深圳国际金融科技大赛正式启动,点击报名 了解详情
写点什么

.NET 不变集合深究

  • 2013-05-06
  • 本文字数:1760 字

    阅读完需:约 6 分钟

自从我们 1 月份报道了不可变集合后,该API 进一步发展,并公布了更多关于内部机制的内容。首先是关于最新版本中做出了哪些改变的概要:

构造函数

尽管不可变集合仍然不提供构造函数,但不必再使用Empty 对象了。以前你会看到这样的代码:

var list = ImmutableList.Empty.Add(1, 2, 3);

新版本中有一个 Create 静态工厂方法,可以使用泛型类型推断。表达式将简化为:

var list = ImmutableList.Create(1, 2, 3);

兼容性

是否实现 IList接口是热议的话题。该接口的支持者认为,与引入 IReadOnlyList之前的库进行交互是十分必要的。而反对者则抱怨对于同样的旧库,没有必要在修改集合的值之前判断 IList.IsReadOnly 是否为 false。

最终,BCL 小组为遗留问题做出妥协,实现了 IList。尽管所有人都同意如果没有 IList.IsReadOnly() 会更好,但现在这背后已经有了太多复杂的因素。

对于公开的不可变类和接口的完整列表,请参阅兼容性表

相等性语义

与其他集合类型一样,不可变集合将只支持引用相等性。 BCL 小组写到

计算集合的值相等性是十分昂贵的,并且对嵌套集合(如 ImmutableDictionary<string, ImmutableList>)相等性的比较也很难定义。最终,提供这种功能在设计不同比较器时会导致更多的问题,就像客户指出的那样。

之前这些集合覆盖了 Object.Equals 而不是 op_equals。

还有人询问是否支持 IStructuralEquatable 。由于其“很难泛化”,BCL 小组已经放弃了支持该接口。例如,在有些场景下可能需要跳过集合中的某些项(如解析器中的空格节点),如果没有特殊的实现,这几乎是不可能的。

而且遗憾的是,为了防止使用继承来添加 IStructualEquatable,不可变类被设计为密封的。

平台支持

不可变集合库专为.NET 4.5 及以后的版本而设计。它利用了新的只读接口,并且开发者不想为旧库维护一个单独的版本。它还可用于 Windows 8 和“protable-net45+win8”配置。

序列化

不可变集合不支持使用 Serializable 特性的旧序列化设计。目前还没有确定是否支持其他序列化设计,如 DataContractSerializer。

本质

不可变集合基于 AVL 树(除栈和队列外)。你可以在不重新复制整个树的情况下在列表的开头、中间或结尾执行插入操作。在维基百科关于持久数据结构这篇文章的树这一节中,有关于这种插入的示例。

不可变散列表也使用了AVL 树。它没有使用在散列值上执行模操作这种普通散列表的桶设计,而是根据原始散列值对树进行排序。这意味着检索操作需要执行一个平均检索时间为O(log n) 的二进制搜索。

请记住在使用多线程操作时,大O 标记法会带来误导。不可变集合的一个替代方案是使用并发集合,它需要昂贵的内部锁来确保线程安全。

不可变集合有一个有意思的特性,它的内部节点并不是不可变的。为了降低构建集合时创建的垃圾,每个节点都起始于一个可编辑的状态。这允许构造函数改变已有的AVL 树,因为它添加了节点,而不是废弃并重新创建。当构造结束、不可变包装器返回的时候,节点将被冻结,以防止进一步修改。

另一个令人感到意外的设计决策是枚举器使用了对象池。在.NET 中,很多枚举器被设计为不会分配任何内存。如果从IList上获取枚举器,需要两次内存分配。但对于List,枚举器是一个结构,不需要任何内存分配。

同样,不可变集合也使用了结构作为枚举器。但由于其内部结构是一个树,因此枚举器需要用一个栈来保存之前访问过的节点,以进行跟踪。为了减少内存分配,将很多这样的栈存储在对象池中(实际也是一个栈),并由一个锁来进行保护。实际上,这是整个不可变集合库中唯一的锁。对枚举器调用Dispose 方法是至关重要的,否则栈将不能返回到对象池中。

更多信息请观看Chinnel 9 的视频不可变集合的内部工作原理

使用建议

在创建不可变集合时,最好是使用Create 函数一次性创建整个集合。这将允许集合对树进行预分配并直接填充节点。第二好的方法是使用builder,不过要调用ToImmutable 才能冻结节点。

在枚举不可变集合中的项时,要使用foreach 循环。由于其内部是树形结构,因此foreach 要比for 快很多。(注:从.NET 2.0 开始,即使是普通的列表,用foreach 读取也比用for 快很多。)

如果集合在创建之后不会改变,那么不可变集合的性能将比用只读包装器保护的普通集合差很多。不可变集合更适用于高效创建与其他集合有少许不同的集合。

查看英文原文 More on Immutable Collections in .NET

2013-05-06 07:052157
用户头像

发布了 59 篇内容, 共 26.3 次阅读, 收获喜欢 3 次。

关注

评论

发布
暂无评论
发现更多内容

三种高级RAG检索方法帮企业告别冗长文档!

神州数码

面向广大中低负载场景,华为云Flexus 云服务器X实例带来“品价比”新选择

轶天下事

服务端性能测试:行业流行性能监控工具介绍

测试人

软件测试 性能测试 自动化测试 测试开发

Open Interpreter利用Code Interpreter实现本地化

神州数码

生成式推荐系统与京东联盟广告-综述与应用

京东零售技术

大模型 企业号2024年7月PK榜

MobPush REST API中的创建推送

MobTech袤博科技

如何熟悉一个陌生系统

京东零售技术

系统 企业号2024年7月PK榜

手把手教你玩转 Nginx 配置

左诗右码

NGINX Ingress Controller

文献解读-长读长测序-第十四期|《作为了解棉花驯化的资源,印度棉(Gossypium herbaceum L. Wagad)基因组》

INSVAST

基因组 基因数据分析 生信服务

HiAI Foundation开发平台,加速端侧AI应用的智能革命

HarmonyOS SDK

HarmonyOS

检索生成(RAG) vs 长文本大模型:实际应用中如何选择?

Baihai IDP

AI LLMs 企业号 7 月 PK 榜 rag 长上下文

自然语言处理与Transformer模型:革新语言理解的新时代

天津汇柏科技有限公司

自然语言处理

多机部署:打造内网服务器集群

左诗右码

Linux 运维

iOS端海外推送最佳实现

MobTech袤博科技

在(Linux)ubuntu下通过GTK调用libvlc开发视频播放器

DS小龙哥

7月月更

隆重推出 NGINX Gateway Fabric 1.0 版本

NGINX开源社区

nginx Kubernetes k8s nginx 开源版 NGINX Gateway Fabric

如何画一个系统的设计图

京东零售技术

架构 企业号2024年7月PK榜

2024年甘肃省7家正规等保测评机构名单汇总

行云管家

网络安全 等保测评 等保测评机构 甘肃

煤矿安全大模型:微调internlm2模型实现针对煤矿事故和煤矿安全知识的智能问答

汀丶人工智能

人工智能 智能问答

电机行业MES生产管理系统--助力电机企业数字化转型

万界星空科技

mes 万界星空科技 电机行业 电机MES 电机工厂

腾讯云WeData全新升级:数据分类分级管理,构建数据安全屏障

腾讯云大数据

wedata

企业自身数据保护技巧你知道多少?用堡垒机可以实现吗?

行云管家

网络安全 数据安全 堡垒机 企业数据安全

低代码拖拽式MES系统数据大屏,重塑智能制造新视界

万界星空科技

数字化转型 mes 数据大屏 万界星空科技mes 电子大屏

天工一刻 | 一文看懂小模型与端侧模型

新消费日报

从美图类场景,看火山引擎数据飞轮如何赋能产品增长

字节跳动数据平台

大数据 用户增长 销售 增长 客户

线索系统性能优化实践

京东零售技术

系统 企业号2024年7月PK榜

.NET 不变集合深究_.NET_Jonathan Allen_InfoQ精选文章