高性能的.NET不可变数组

最新发布的.NET不可变集合中包含了ImmutableArray\u0026lt;T\u0026gt;,一种在只读、索引化的场景中比ImmutableList\u0026lt;T\u0026gt;更快速的选择。ImmutableList\u0026lt;T\u0026gt;在设计时选择了一种平衡的方案。由于其复杂的内部结构,添加新项只能是O(log n)的操作。同样,通过索引读取某项也要耗费O(log n)的时间。

\

ImmutableArray\u0026lt;T\u0026gt;则没有这么复杂。它只是一个包装了数组的结构。用ildasm可以看到,它不包含任何其他字段。这意味着从不可变数组中读取只需要O(1)的时间。相反,向不可变数组添加一项则需要对实际数组进行完全拷贝,为O(n)操作。

\

Immo Landwerth提出了以下建议:

\
\

使用不可变数组的理由:

\
  • 极少更新数据,并且元素数量很小(小于16)\
  • 对迭代数据的性能要求很高\
  • 有很多不可变集合的实例,并且无法负担将它们全放在树中的开销。\

仍然使用不可变列表的理由:

\
  • 更新数据比较常见,或者元素数量预计不会太小\
  • 对更新集合的性能要求比迭代要高\
\

作为一个值类型,ImmutableArray\u0026lt;T\u0026gt;在创建时不需要显式初始化。此时,结构将检测到内部空指针,其行为就像是长度为0的数组。

\

重大改变

\

不可变集合正处于开发过程中,重大变更时有发生。这一次,我们看到Create\u0026lt;T\u0026gt;(IEnumerable\u0026lt;T\u0026gt; items)函数更名为“From”。

\

Immo写到,

\
\

我们发现接受IEnumerable\u0026lt;T\u0026gt;参数的重载可能会产生意想不到的结果。你可能认为要通过其他集合创建集合可以使用接受IEnumerable\u0026lt;T\u0026gt;参数的重载:

\

但你最终创建的是ImmutableList\u0026lt;List\u0026lt;string\u0026gt;\u0026gt;而不是Immutable\u0026lt;string\u0026gt;,这是因为在进行重载决策时,参数重载的优先级要高于从List\u0026lt;string\u0026gt;到IEnumerable\u0026lt;string\u0026gt;的隐式转换。

\

因此我们决定将所有操作IEnumerable\u0026lt;T\u0026gt;的工厂方法改名为From,以消除这种歧义。

\
\

最初的IImmutableList\u0026lt;T\u0026gt;包含一个ValueComparer属性,并匹配WithComparer方法。为了让ImmutableArray\u0026lt;T\u0026gt;保持为一个简单的包装器,就有必要在IImmutableList\u0026lt;T\u0026gt;接口中移除它们。

\

扩展方法GetValueOrDefault曾经接受一个IDictionary\u0026lt;TKey, TValue\u0026gt;或IReadOnlyDictionary\u0026lt;TKey, TValue\u0026gt;。如果实际的类同时实现了这两个接口就会引起编译器错误,因此用只接受IImmutableDictaionary\u0026lt;TKey, TValue\u0026gt;的版本进行了替换。

\

其他改变

\

IImmutableSet\u0026lt;T\u0026gt;新增了TryGetValue方法。如果使用了比较器如StringComparer.OrdinalIgnoreCase,并且想得到集中的实际值而不仅仅是判断是否存在等价的元素时,就需要使用该方法了。

\

不可变集合仍然是预览版,并且不允许在生产中使用。它们目前可用于.NET 4.5、Windows Store、Windows Phone 8和Portable Class Library。

\

数组的性能

\

Jon Skeet最近测试了数组的性能并发现了一些有趣的结果。用包装器包装数组竟然可以使它们能够更快地写入。对一个包含100项的数组进行1亿次写入,字符串数组用了40.865秒,而包装的字符数组只用了29.338秒。读取速度两者差不多,字符数组用了12秒,包装的数组用了11.843秒。

\

其原因要追溯到Java了。Java的数组是协变的,也就是说可以将一个String[]传递给任何期望Object[]的参数或变量。.NET的运行时CLR要设计为支持Java,所以也支持协变数组。因此在每次写入数组时CLR都需要执行一次类型检查。

\

Jon Skeet的数组包装器与我们上面提到的ImmutableArray中使用的并不相同。它在内部对数组中的每一项使用了基于结构的包装器。由于它只是一个包含了指针的结构,因此并不比数组中存储的普通引用耗费更多的空间。但其设计可以使CLR的JIT编译器忽略类型检查。

\

查看英文原文High Performance Immutable Arrays in .NET

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值