.NET开发中一个常见的误区是,认为IEnumerable或ReadOnlyCollectionl类型的变量是线程安全的。微软的Andrew Arnott解释道:
如果有人给你一个ReadOnlyCollection<T>、IReadOnlyList<T>或IEnumerable<T>,唯一能保证的是你无法修改它们的数据,但却不能保证给你集合的人不会修改。不过对于数据不会改变这点,你往往需要一些信心。这些类型在改变内容时不会提供事件通知,并且如果在你迭代其内容的时候,集合真的改变了,这是否会发生在不同的线程呢?这种行为将造成应用程序中的数据崩溃和随机异常。
要在你想用IEnumerable或ReadOnlyCollection的地方提供真正线程安全的集合,微软BCL小组提供了一组不可变集合的预览版。基于函数式编程的技术,对于那些通常会改变集合的方法将会创建一个新集合来代替。为了提高效率,可能会在新旧集合之间进行数据共享。
不可变集合一个有意思的特点是没有公共构造函数。相反,它们总是以ImmutableXxx<T>.Empty作为开始。Andrew写到
使用静态Empty属性与传统模式相背离,但这么做是有原因的。构造函数必须要分配一个对象,但由于这些集合的不可变性,新的对象永远只能表示空的列表。鉴于修改集合会创建新的集合,因此使用构造函数会导致创建多个表示空列表的对象,这显然是种浪费。静态属性返回空列表的单例,应用程序中的所有代码都可以共享该单例。
建造者和集合
由于内存分配,构建一个不可变集合是相当昂贵的。我们已经在字符串(即字符的不可变集合)身上看到了这一点。为了缓解这一点,不可变集合将暴露一个ToBuilder方法,返回一个可以廉价修改的建造者对象。得到之后,还可以简单地使用ToImmutable再次得到不可变集合。
性能
不可变集合的性能可能会非常棘手。如下表所示,大多数不可变集合的时间复杂度都相当不错,并且是稳定的,不必担心在集合内部数组的最大尺寸会触发集合的完全拷贝。与普通集合不同,不可变集合中的项如果被移除,将会释放不用的空间。
但还是会有成本。每个操作都要在内存中分配另一个对象,给GC带来压力。最大的胜利是在创建集合的快照拷贝时。但最终的建议仍然是:使用最简单的代码完成工作,并在必要的时候调整性能。 该预览版可通过Microsoft.Bcl.Immutable NuGet包下载。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
相关推荐
-
.NET架构师:函数式语言做领域驱动设计
Scott一位.NET架构师,同时也是掌握函数式编程的作者,他很欣赏函数式编程,对于Scott来说,面向对象编程的那些概念也很恐怖,比如多态、泛型、继承、协变等。
-
软件开发就像炒股 关键看你怎么选股票!
本文作者Paulo Ortins在这里分享了对于选择哪种编程语言作为软件开发工作的起点的话题,并阐述了自己的观点。
-
增进离岸Java开发效率的十个提示
近日,Cygnet Infotech公司发布了一篇博文,谈到了如何增进离岸Java开发的效率。众多的ISV与软件厂商总是在不断寻找能以最低的代价实现其业务目标的解决方案。
-
SaaS平台上的多线程控制与故障处理
内部部署的COBOL程序成功地转化为基于Java的软件即服务应用程序,开发人员应该小心提防多线程问题。