以List为例浅谈C#的学习方法
前言:关于学习方法的讨论其实是个比较模糊的概念,对于List的介绍的资料其实已经很多了,但是一般是介绍List本身,我打算分享的是,以温故List为例,来获取新知识的这么一个过程。这里的新知识也不是什么新知识,依旧是算法、泛型、迭代器和GC回收机制等相关术语,只不过通过对List再分析,对这些东西的运用有了些新的认知,我要分享的就是再分析的这么一个过程,姑且允许我将其称为学习方法吧,最起码它是比较适合我的一种学习方法。另外,如果对List已经了解很深或者兴趣不大的话,可以直接跳过1、2节一大堆无聊的测试,直接看总结,甚至跳过此文也未尝不可。
1、 抛砖(List的关键属性Capacity)
前言已经说明是温故List,所以List是什么我也不打算花篇幅再次介绍(更何况一点点的介绍其扩容机制、迭代器和一些内部方法篇幅也会比较大,那就成了介绍List本身了,个人也不见得能总结得多好),这里我温故的就是List的扩容机制。
用反编译工具看过List<T>源码的同学,应该都知道List对象在创建的时候其私有变量_defaultCapacity的值是4。
(此截图来源与ILspy打开的List<T>源码部分,以下关于List<T>的源码部分均是如此)
这个地方让我很长一段时间以为List对象在创建的时候就已经为它内部的数组对象,分配了4个元素,以后调用Add方法就以Capacity*2的线性速度增长,可事实狠狠的打了我一把脸,且看下面这段代码及其运行结果:
回过头来再看源码,发现Capacity属性返回的是内部数组元素的长度,所以刚开始初始化的时候并没有被私有变量初始化,而且就算初始化的时候想给数组4个元素,也不知道List<T>对象中T的实例(T为引用类型的情况下),该分配多少内存CLR是不知道的。
所以我猜测_defaultCapacity赋值给Capacity是在List首次调用Add方法,或者带元素初始化的时候,果不其然,看下面这段代码:
找到源码验证一下:
那么扩容的机制也就理所当然的被我们找到了,就是EnsureCapacity方法,this._szie是当前List元素个数,this._items是内部数组根据Capacity扩容后的数组长度,扩容触发的条件是this._size+1>this._items.Length, 总结说来就是,Capacity的初始值是0,在不主动改变Capacity的情况下使用Add方法会初始化为4,当List元素达到4且继续调用Add的话Capacity就会乘以2变成8,然后如此反复,直到达到2146435071(应该是2^31-1)为止。
2、 引玉(主动操作Capacity是否可带来性能的提升)
通过第1节的分析,想要Add到1亿级别的数量,需要扩容27次,2^27破亿(Capacity从0到4一次,从4到2^27花26次)
那么,正常初始化1亿Int32类型数据需要耗时多久呢?通过下面这段代码可以发现是681ms。
假如我把Capacity初始值设置为1亿,省去那26次扩容带来的时间损耗呢?
为了避免电脑CPU时间段的差异对结果造成影响,我分别运行了3次,不初始化Capacity的情况下耗时700ms左右,初始化Capacity的情况下耗时450ms左右,这么说来是可以带来一定性能的提升的。那么把Capacity设置为3千万,让它扩容两次破亿:
这么一看减少扩容次数是可以带来性能上的提升的。但是这里List集合是值类型的集合,换成引用类型又当如何呢?看如下代码:
减少扩容次数后:
结论依旧是可以带来性能上的提升的。但是个人觉得实际应用中通过设置Capacity去提升性能是不可取的,一方面是使用了对性能的提升并没有显著的改善,况且上亿级别的数据需要缓存的话,一般会使用专门的缓存服务器,另一方面是数据量不好确认,Capacity的设置很难合理,而且使用List的初衷,本来就是为了方便。而且看下面这段代码,我把Test的实例对象放进循环里(实际应用中这也更符合测试思路,毕竟上面的测试List存的都是同一个实例对象),还不等你提升性能,CLR托管内存就爆了,GC都回收不过来了。
3、 总结(知新)
对这次List的重温,更全面的了解其扩容机制,此间带来的收获主要在以下几点:
(1) Capacity的设置确实能为List的初始化带来性能的提升,但是一般情况下不使用这种方式。
(2) List扩容的这种机制其实很巧妙,在自定义集合中有值得借鉴的地方。
(3) 意识到托管内存不宜缓存大量数据,同时引导我再次了解GC处理机制。
(4) List内部变量在方法体的使用中,使用了大量的lock规避引用冲突,这种严谨在多线程、iis线程池等引用的过程中,也是非常值得借鉴的。
(5) 为以后学习其它类似特性的对象提供了思路,假如我现在需要学习一个新的组件或框架,我首先会寻找它的API文档和使用说明、动手测试、大胆猜想、借助源码以及再测试来求证……。
以List为例浅谈C#的学习方法的更多相关文章
- 以用户注册功能模块为例浅谈MVC架构下的JavaWeb开发流程
JavaWeb应用开发,撇开分布式不谈,只讨论一个功能服务应用的开发,无论是使用原生的Servlet/JSP方案,还是时下的SSM架构,都有一套经过工程实践考验的最佳实践,这综合考虑了团队协作.项目管 ...
- 以图像分割为例浅谈支持向量机(SVM)
1. 什么是支持向量机? 在机器学习中,分类问题是一种非常常见也非常重要的问题.常见的分类方法有决策树.聚类方法.贝叶斯分类等等.举一个常见的分类的例子.如下图1所示,在平面直角坐标系中,有一些点 ...
- [转]以新浪为例浅谈XSS
随着网络时代的飞速发展,网络安全问题越来越受大家的关注,而SQL注入的攻击也随着各种防注入的出现开始慢慢的离我们而去,从而XSS跨站脚本攻击也慢慢的开始在最近几年崛起,也应对了’没有绝对的安全’这句话 ...
- 浅谈WebService的版本兼容性设计
在现在大型的项目或者软件开发中,一般都会有很多种终端, PC端比如Winform.WebForm,移动端,比如各种Native客户端(iOS, Android, WP),Html5等,我们要满足以上所 ...
- 浅谈Hybrid技术的设计与实现第三弹——落地篇
前言 接上文:(阅读本文前,建议阅读前两篇文章先) 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 根据之前的介绍,大家对前端与Native的交互应该有一些简单的认识了,很多 ...
- 浅谈Hybrid技术的设计与实现第二弹
前言 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 浅谈Hybrid技术的设计与实现第三弹——落地篇 接上文:浅谈Hybrid技术的设计与实现(阅读本文前,建议阅读这个先) ...
- 浅谈php生成静态页面
一.引 言 在速度上,静态页面要比动态页面的比方php快很多,这是毫无疑问的,但是由于静态页面的灵活性较差,如果不借助数据库或其他的设备保存相关信息的话,整体的管理上比较繁琐,比方修改编辑.比方阅读权 ...
- jsp内置对象浅谈
jsp内置对象浅谈 | 浏览:1184 | 更新:2013-12-11 16:01 JSP内置对象:我们在使用JSP进行页面编程时可以直接使用而不需自己创建的一些Web容器已为用户创建好的JSP内置对 ...
- Android性能优化的浅谈
一.概要: 本文主要以Android的渲染机制.UI优化.多线程的处理.缓存处理.电量优化以及代码规范等几方面来简述Android的性能优化 二.渲染机制的优化: 大多数用户感知到的卡顿等性能问题的最 ...
随机推荐
- struts2 内容记录
多xml文件配置 在开发过程中我们经常会将每一张表(如:user表)的struts.xml文件分开,便于管理,故需要建立struts_user.xml文件管理请求等.那么需要用到inculde标签. ...
- python操作Mysql基础
import pymysql #不修改数据 def no_data_change(): db=pymysql.connect('host','user','pw','db_name') #host,u ...
- Qt---Xml文件解析
本文我们通过一个读取Xml文件的小例子来学习QXmlStreamReader. Xml 简介 Xml的全称是可扩展标记语言(EXtensible Markup Language),同HTML一样是一种 ...
- Anaconda 安装 Python 库(MySQLdb)的方法
[已解决]Anaconda 安装 Python 库(MySQLdb)的方法 zoerywzhou@163.com http://www.cnblogs.com/swje/ 作者:Zhouwan 201 ...
- Ceph luminous 安装配置
Ceph luminous 安装配置 #环境centos7 , Ceph V12 openstack pike 与 ceph 集成 http://www.cnblogs.com/elvi/p/7897 ...
- 导入Excel 文件(图片和文字)NPOI+BootStrap fileinput 插件 的结合使用
1.页面代码: <!DOCTYPE html><html><head> <meta name="viewport" content=&qu ...
- 51Nod 2006 飞行员配对(二分图最大匹配)
链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=2006 思路: 二分匹配 注意n m的关系 代码: #include ...
- PF_RING install in centos7
很多centos7是最小化安装. 这样很多kernel就没有安装全,而且很多开发库也没有. 在安装PF_RING过程中,会缺少很多依赖. 首先安装依赖包: yum -y install numactl ...
- jq,返回上一页,小记history.back(-1)和history.go(-1)区别
<input type="button" name="back" value="重新填写" onclick="javascr ...
- Centos-6.5 + python3 + mysql5.6 环境搭建
注意:Centos6.5 是刚装好的系统 yum install lrzsz (ftp上传和下载) yum install -y gcc yum install -y gcc gcc-c++ ...