以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的性能优化 二.渲染机制的优化: 大多数用户感知到的卡顿等性能问题的最 ...
随机推荐
- Redis全面介绍
最近重新认识了一下Redis,借着这个机会,也整理一篇算是比较详尽和全面的文章吧. 缓存 缓存就是数据交换的缓冲区(称作Cache)——摘自百度百科.无论是在计算机硬件体系结构还是软件体系结构中, ...
- [转载] 解读ClassLoader
转载自http://www.iteye.com/topic/83978 ClassLoader一个经常出现又让很多人望而却步的词,本文将试图以最浅显易懂的方式来讲解 ClassLoader,希望能对不 ...
- Python手动实现k-means
import numpy as np import matplotlib.pyplot as plt def kmeans(data, cluster_num, method='mean'): poi ...
- P1457 城堡 The Castle
轻度中毒 原题 :The Castle 以下为题解部分:明明辣么简单的一道题,硬是搞了1.5h,WTF?以下列出本题的一些要点. 搜索(DFS)嘛,染色嘛,统计大小嘛,很容易想,也很更易处理. 接下来 ...
- listview相关代码整理
虽然listview已经慢慢被替代了, 不过还是整理下 , 留作纪念吧 /** * 获取 listview 实际滚动的距离. [ 相对于listview的第一个项目左上角.] * * @return ...
- 项目实战9—企业级分布式存储应用与实战MogileFS、FastDFS
企业级分布式存储应用与实战-mogilefs 环境:公司已经有了大量沉淀用户,为了让这些沉淀用户长期使用公司平台,公司决定增加用户粘性,逐步发展基于社交属性的多样化业务模式,决定开展用户讨论区.卖家秀 ...
- 十三、Hadoop学习笔记————Hive安装先决条件以及部署
内嵌模式,存储于本地的Derby数据库中,只支持单用户 本地模式,支持多用户多会话,例如存入mysql 下载解压hive后,进到conf路径,将模板拷贝 出现该错误表示权限不够 该目录未找到 新建一个 ...
- Ckeditor与Ckfinder的配合使用,上传图片、水印、修改图片名字为当前日期 asp.net
为了配置出来上传功能,并且还添加水印,修改图片的名字为日期,真的头疼了很久,现在来分享一下自己所做的,也算一点小小的成就吧,顺带帮帮很多还在弄这个的猿们.我是分别用了两种方法.先说低版本的Versio ...
- CNCC2017中的深度学习与跨媒体智能
CNCC2017中的深度学习与跨媒体智能 转载请注明作者:梦里茶 目录 机器学习与跨媒体智能 传统方法与深度学习 图像分割 小数据集下的深度学习 语音前沿技术 生成模型 基于贝叶斯的视觉信息编解码 珠 ...
- Mysql--触发器的操作
1.为什么使用触发器 2.创建触发器 2.1 创建有一条执行语句的触发器 例子:在数据库company中存在两个表对象:部门表(t_dept)和日记表(t_diary),创建触发器实现向部门表中插入记 ...