快速入门系列--CLR--03泛型集合
.NET中的泛型集合
在这里主要介绍常见的泛型集合,很多时候其并发时的线程安全性常常令我们担忧。因而简述下.NET并发时线程安全特性,其详情请见MSDN。
- 普通集合都不支持多重并发写操作
- 部分支持单线程写和并发读操作
- 同时.NET4添加了大量并发集合
首先介绍常见的泛型集合接口,其大部分都位于System.Collection.Generic命名空间。
- IEnumerable<T>,其可以获取一个IEnumerator<T>迭代器,如果从数据库的角度来看,前者是表,后者是游标,同时这两个接口是唯一具有可变性的集合接口。
- ICollection<T>,它扩展了IEnumerable<T>,添加了Count和IsReadOnly属性,Add和Remove等操作方法,Contains等判定函数,所有的标准泛型集合都实现了该接口。
- IList<T>,提供定位功能,包括一个索引器、Insert和RemoveAt,我们通常认为可以通过索引对该泛型集合进行随机访问。、
- IDictionary<TKey, TValue>,表示键值对集合,扩展了ICollection<KeyValuePair<TKey, TValue>>,取值可以用TryXXX方式。
- ISet<T>表示唯一值集,包含大量集合操作:交、并、补。
接下来介绍具体的集合泛型集合类型,在实际中需要根据具体场景选择最适合的集合类型。
- List<T>,其是列表的默认选择,内含一个数组,并且提供列表的逻辑大小Count和后台数组的大小Capacity,当数组满了时,会进行扩容。由于是连续型的数据结构,其添加删除操作的成本较高,提供二分查找,查找效率高。同时,其Sort操作会修改原始列表的内容,与OrderBy不同,并且Sort是不稳定的,会出现相等元素顺序不同的情况。
- 数组,最基础的集合,均派生自System.Array,包括一维数组T[10],二维数组T[10, 20]等,通过Array类的静态方法进行ConvertAll、FindAll和BinarySearch等操作。
- Colletion<T>,位于System.Colletion.ObjectModel命名空间,为BindingList<T>和ObservableCollection<T>等扩展类型提供基类。与双向绑定相关的集合类型,注意它们只会在包装器发生变化发出通知,而基础列表改变时不会引发任何事件。
- ReadOnlyCollection<T>和ReadOnlyObservableCollection<T>,其也类似于包装器,后者实现了INotifyCollectionChanged, INotifyPropertyChanged两个接口。
- Dictionary<TKey, TValue>,使用散列表,查找性能的优劣取决于散列函数的优劣,默认使用Equals和GetHashCode,可以通过制定IEqualityComparer<TKey>作为参数。
- SortList<TKey, TValue>和SortedDictionary<TKey, TValue>,两者都是字典类,前者内部维护一个排序的数组,添加删除操作的事件复杂度为O(n),后者内部维护一个红黑树,添加删除操作事件复杂度为O(log n),但会消耗更多的堆内存,使用IComparer<TKey>作比较。
- HashSet<T>,是不含值的Dictionary<,>,具有相同性能特性,并且所维护顺序一般与添加顺序无关。
- SortedSet<T>,是没有值得SortedDictionary<,>,维护一个红黑树,添加删除和检查操作的事件复杂度为O(log n)。提供GetViewBetween方法返回介于原始集上下限之间的另一个SortedSet<T>,注意这是一个动态的视图,会随着原始集的改变而改变。尽管看起来很方便,但需要注意的是"天下没有免费的午餐",为保持内部一致性,操作的代价更大。
- Queue<T>,构建一个环形缓冲区,实际维护一个基础数组,包含两个索引,分别记住入队和出队的位置(Slot),如果入队指针追上出队指针,则进行扩容。提供Enqueue、Dequeue、Peek等方法进行入队、出队、查看操作。
- Stack<T>,其实现更简单,可以看做是一个提供Push、Pop、Peek操作的List<T>。
最后介绍并行集合,也就是线程安全的集合。(注意所有的并发类型都未实现IList<T>接口)
- IProducerConsumerCollection<T>和BlockingCollection<T>,前者是生产者/消费者模型中数据存储的抽象,后者是其包装类,使用ConcurrentQueue<T>作为后台存储,提供ToArray方法获得集合当前状态快照,TryXXX方法允许有效的失败模式减少对锁的需求。(例如,当队列中只有一个项时,两个线程同时判断它是否有项,并且都返回true,这是一个线程执行了出队操作,而另外一个线程在执行出队操作时,将抛出异常,因而需要对验证队列是否有项操作和有项就出队操作作为一个整体,需要添加锁)
- ConcurrentBag<T>,ConcurrentQueue<T>,ConcurrentStack<T>,它们是对IProducerConsumerCollection<T>的实现,其GetEnumerator()方法返回集合快照,迭代时可以改变集合,但该改变不会反应到迭代器中。
- ConcurrentDictionary<TKey, TValue>, 实现了IDictionary<TKey, TValue>接口。支持并发的读写和线程安全的迭代,但不同是,其在迭代过程中对字典的改变不能确定是否反应到迭代器上。
小节:在日常工作中,当遇到需要并发操作非集合类型的全局变量时,需要使用锁来处理;而当是集合类型时,就需要使用对应的并行集合类来处理,其能很好的TPL协作在一起。尤其在使用非线程安全的字典类进行并发操作时,有时会出现死循环等情形,尤其需要注意。
Tip:where T:new()
参考文献
- 版)[M]. 北京:人民邮电出版社, 2014. 469-483
快速入门系列--CLR--03泛型集合的更多相关文章
- 快速入门系列--WebAPI--04在老版本MVC4下的调整
WebAPI是建立在MVC和WCF的基础上的,原来微软老是喜欢封装的很多,这次终于愿意将http编程模型的相关细节暴露给我们了.在之前的介绍中,基本上都基于.NET 4.5之后版本,其System.N ...
- 快速入门系列--MVC--01概述
虽然使用MVC已经不少年,相关技术的学习进行了多次,但是很多技术思路的理解其实都不够深入.其实就在MVC框架中有很多设计模式和设计思路的体现,例如DependencyResolver类就包含我们常见的 ...
- WPF快速入门系列(4)——深入解析WPF绑定
一.引言 WPF绑定使得原本需要多行代码实现的功能,现在只需要简单的XAML代码就可以完成之前多行后台代码实现的功能.WPF绑定可以理解为一种关系,该关系告诉WPF从一个源对象提取一些信息,并将这些信 ...
- WPF快速入门系列(1)——WPF布局概览
一.引言 关于WPF早在一年前就已经看过<深入浅出WPF>这本书,当时看完之后由于没有做笔记,以至于我现在又重新捡起来并记录下学习的过程,本系列将是一个WPF快速入门系列,主要介绍WPF中 ...
- es6 快速入门 系列 —— 类 (class)
其他章节请看: es6 快速入门 系列 类 类(class)是 javascript 新特性的一个重要组成部分,这一特性提供了一种更简洁的语法和更好的功能,可以让你通过一个安全.一致的方式来自定义对象 ...
- 快速入门系列--WebAPI--01基础
ASP.NET MVC和WebAPI已经是.NET Web部分的主流,刚开始时两个公用同一个管道,之后为了更加的轻量化(WebAPI是对WCF Restful的轻量化),WebAPI使用了新的管道,因 ...
- 快速入门系列--WebAPI--03框架你值得拥有
接下来进入的是俺在ASP.NET学习中最重要的WebAPI部分,在现在流行的互联网场景下,WebAPI可以和HTML5.单页应用程序SPA等技术和理念很好的结合在一起.所谓ASP.NET WebAPI ...
- 快速入门系列--MVC--02路由
现在补上URL路由的学习,至于蒋老师自建的MVC小引擎和相关案例就放在论文提交后再实践咯.通过ASP.NET的路由系统,可以完成请求URL与物理文件的分离,其优点是:灵活性.可读性.SEO优化.接下来 ...
- 快速入门系列--MVC--07与HTML5移动开发的结合
现在移动互联网的盛行,跨平台并兼容不同设备的HTML5越来越盛行,很多公司都在将自己过去的非HTML5网站应用渐进式的转化为HTML5应用,使得一套代码可以兼容不同的物理终端设备和浏览器,极大的提高了 ...
- Qt快速入门系列教程目录
Qt快速入门系列教程目录
随机推荐
- eclipse/myeclipse sublime 实时更新文件改变
情形: 在使用eclipse/myeclipse开发的时候, 像JS 或者HTML 以及一些操作时,sublime 的效率比eclipse/myeclipse要快,所以我们就可以使用这两者一起开发. ...
- nodejs中Stream的理解
在nodejs中可以通过fs模块读写文件,我们来看下fs模块提供的接口: fs.readFile(filename, callback) 异步读取文件. filename是读取文件的文件名,如果是相对 ...
- Eclipse中支持js提示
使用eclipse自带的插件,无需另外安装插件,具体步骤如下 1.打开eclipse→Windows→Preferences→Java→Editor→Content Assist 修改Auto Act ...
- Java SE、Java EE、Java ME
Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程序.J ...
- 安装CAS服务器
1.简介 参考: http://www.coin163.com/java/cas/cas.html CAS主要用于多系统单点登录,属于WEB SSO.SSO体系主要角色有三种:User(多个),WEB ...
- .Net mvc 后台传单引号错误'
今天调试半天程序 结果出现JS 无法eval() 网上找个半天解决办法无果 最后 是因为后台输出单引号’ 到前台为' 解决办法 给一个隐藏文本框或者标签赋值 再取出来就能显示单引号了
- Apache HTTP Server 2.2.26 发布
Apache遗留产品线2.2.26发布.2013-11-13 之前的版本是2013-07-02的2.2.25 同样先在开发目录下放出下载,然后放到正式目录下.修正了大量的Bug.目前的稳定版2.4系列 ...
- HTML5优秀图表控件
不管是哪个领域的开发,都有机会用到图表来做统计分析,以更直观的表现形式来代替传统的文字.在以前,图表控件主要有使用程序代码生成的静态图片,或者是使用flash实现的图表控件. 在HTML5非常流行的当 ...
- Angularjs路由需要了解的那点事
Angularjs路由需要了解的那点事 我们知道angularjs是特别适合单页面应用,为了通过单页面完成复杂的业务功能,势必需要能够从一个视图跳转到另外一个视图,也就是需要在单个页面里边加载不同的模 ...
- 浅谈Excel开发:四 Excel 自定义函数
我们知道,Excel中有很多内置的函数,比如求和,求平均,字符串操作函数,金融函数等等.在有些时候,结合业务要求,这些函数可能不能满足我们的需求,比如我想要一个函数能够从WebService上获取某只 ...