【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

.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:051574
用户头像

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

关注

评论

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

卷不动的IT从业人的新赛道在哪里?

小魏写代码

Mac 双系统神器_Mac虚拟机软件 | Parallels Desktop 19

晴雯哥

TCL电视全球出货量势头强劲,全球品牌影响力持续增强

科技热闻

亮相2023全球工业互联网大会,天翼云为工业夯实算力底座!

天翼云开发者社区

人工智能 云计算

一文带你彻底了解JMX

高端章鱼哥

RestTemplat WebClient

在Linux上使用Docker实现应用程序打包和分发

这我可不懂

Docker Linux

初识搜索:百度搜索产品经理的第一课

百度Geek说

百度搜索 企业号10月PK榜 搜索产品经理

Dapp钱包智能合约链上质押模式系统开发

l8l259l3365

绿野仙踪不仅是童话,还是便宜又好用的产品测试法!

鼎道智联

AI ChatGPT

1024程序员节 | 华为与开发者共筑技术新高地

新消费日报

交易所开发 dapp开发:DeFi领域取得成功的综合指南

区块链软件开发推广运营

交易所开发 dapp开发 区块链开发 链游开发 NFT开发

NFT链游系统技术开发/NFT元宇宙链游开发/Defi/应用DAPP

V\TG【ch3nguang】

「支持M1」Ableton Live 11 Mac破解版 附 Ableton Live 11破解安装教程

晴雯哥

Autodesk AutoCAD(CAD2024)中文特别版mac/win

影影绰绰一往直前

AutoCAD 2024下载 AutoCAD破解版 AutoCAD 激活版

扩展Nginx的无限可能:掌握常见扩展模块和第三方插件的使用方法

互联网工科生

nginx

数字先锋| 天翼云助力金州教育云平台智慧升级,让优质教育资源“活起来”!

天翼云开发者社区

云计算 大数据

一步步带你剖析Java中的Reader类

华为云开发者联盟

Java 开发 华为云 华为云开发者联盟

Easysearch 容量规划建议

极限实验室

数据库 搜索引擎 监控系统 easysearch

招募令丨面向领域应用的 Python 编程教学,让和鲸社区成为您的扩展课堂

ModelWhale

Python 编程 心理学 数据科学 交叉学科

在Kubernetes中实现gRPC流量负载均衡

树上有只程序猿

golang Kubernetes

7种不同类型的产品经理工具:一文读懂PM必学的办公软件!

彭宏豪95

产品经理 产品管理 在线白板 办公软件 在线协作

日志

xujiangniao

规范预算执行,构建企业预算管理一体化建设

智达方通

预算执行 企业预算管理

云网融合再加码!天翼云SD-WAN PON来了!

天翼云开发者社区

云计算

Microsoft Office 2016-2021中文激活版

影影绰绰一往直前

office 2016 office下载 Microsoft Office 2019

WinX HD Video Converter for mac (视频格式转换器) 6.8.1激活版

mac

苹果mac Windows软件 视频转换器 WinX HD Video Converter

达芬奇DaVinci Resolve Studio 18 密钥激活资源最新

mac大玩家j

Mac软件 达芬奇18 视频调色工具

Macos必备 VM虚拟机:VMware Fusion Pro 13序列号激活 附 VM 13安装激活教程 支持M1 【亲测可用】

晴雯哥

用Rust实现UDP Echo服务器和客户端

胡译胡说

rust 网络 TCP/IP UDP协议

直播预告 | YashanDB 2023年度发布会正式定档11月8日,邀您共同见证国产数据库发展实践!

墨天轮

数据库 深圳 国产数据库 yashandb

Proto-Mock:你的 Protobuf 随机数据生成利器

。。。

前端 Node protobuf

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