第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字
一. 各类数据结构比较及其线程安全问题
1. Array(数组):
分配在连续内存中,不能随意扩展,数组中数值类型必须是一致的。数组的声明有两种形式:直接定义长度,然后赋值;直接赋值。
缺点:插入数据慢。
优点:性能高,数据再多性能也没有影响
特别注意:Array不是线程安全,在多线程中需要配合锁机制来进行,如果不想使用锁,可以用ConcurrentStack这个线程安全的数组来替代Array。
{
Console.WriteLine("---------------------------01 Array(数组)-----------------------------------");
//模式一:声明数组并指定长度
int[] array = new int[];
//数组的赋值通过下标来赋值
for (int i = ; i < array.Length; i++)
{
array[i] = i + ;
}
//数组的修改通过下标来修改
array[] = ;
//输出
for (int j = ; j < array.Length; j++)
{
Console.WriteLine(array[j]);
}
//模式二:直接赋值
string[] array2 = new string[] { "二胖", "二狗" };
}
2. ArrayList(可变长度的数组)
不必在声明的时候指定长度,即长度可变;可以存放不同的类型的元素。
致命缺点:无论什么类型存到ArrayList中都变为object类型,使用的时候又被还原成原先的类型,所以它是类型不安全的,当值类型存入的时候,会发生装箱操作,变为object引用类型,而使用的时候,又将object类型拆箱,变为原先的值类型,这尼玛,你能忍?
结论:不推荐使用,建议使用List代替!!
特别注意:ArrayList不是线程安全,在多线程中需要配合锁机制来进行。
{
Console.WriteLine("---------------------------02 ArrayList(可变长度的数组)-----------------------------------");
ArrayList arrayList = new ArrayList();
arrayList.Add("二胖");
arrayList.Add("马茹");
arrayList.Add();
for (int i = ; i < arrayList.Count; i++)
{
Console.WriteLine(arrayList[i] + "类型为:" + arrayList[i].GetType());
}
}
3. List<T> (泛型集合) 推荐使用
内部采用array实现,但没有拆箱和装箱的风险,是类型安全的
特别注意:List<T>不是线程安全,在多线程中需要配合锁机制来进行,如果不想使用锁,可以用ConcurrentBag这个线程安全的数组来替代List<T>
{
Console.WriteLine("---------------------------03 List<T> (泛型集合)-----------------------------------");
List<string> arrayList = new List<string>();
arrayList.Add("二胖");
arrayList.Add("马茹");
arrayList.Add("大胖");
//修改操作
arrayList[] = "葛帅";
//删除操作
//arrayList.RemoveAt(0);
for (int i = ; i < arrayList.Count; i++)
{
Console.WriteLine(arrayList[i]);
}
}
4. LinkedList<T> 链表
在内存空间中存储的不一定是连续的,所以和数组最大的区别就是,无法用下标访问。
优点:增加删除快,适用于经常增减节点的情况。
缺点:无法用下标访问,查询慢,需要从头挨个找。
特别注意:LinkedList<T>不是线程安全,在多线程中需要配合锁机制来进行。
{
Console.WriteLine("---------------------------04 ListLink<T> 链表-----------------------------------");
LinkedList<string> linkedList = new LinkedList<string>();
linkedList.AddFirst("二胖");
linkedList.AddLast("马茹");
var node1 = linkedList.Find("二胖");
linkedList.AddAfter(node1, "三胖");
//删除操作
linkedList.Remove(node1);
//查询操作
foreach (var item in linkedList)
{
Console.WriteLine(item);
}
}
5. Queue<T> 队列
先进先出,入队(Enqueue)和出队(Dequeue)两个操作
特别注意:Queue<T>不是线程安全,在多线程中需要配合锁机制来进行,如果不想使用锁,线程安全的队列为 ConcurrentQueue。
实际应用场景:利用队列解决高并发问题(详见:http://www.cnblogs.com/yaopengfei/p/8322016.html)
{
Console.WriteLine("---------------------------05 Queue<T> 队列-----------------------------------");
Queue<int> quereList = new Queue<int>();
//入队操作
for (int i = ; i < ; i++)
{
quereList.Enqueue(i + );
}
//出队操作
while (quereList.Count != )
{
Console.WriteLine(quereList.Dequeue());
}
}
6. Stack<T> 栈
后进先出,入栈(push)和出栈(pop)两个操作
特别注意:Stack<T>不是线程安全
{
Console.WriteLine("---------------------------06 Stack<T> 栈-----------------------------------");
Stack<int> stackList = new Stack<int>();
//入栈操作
for (int i = ; i < ; i++)
{
stackList.Push(i + );
}
//出栈操作
while (stackList.Count != )
{
Console.WriteLine(stackList.Pop());
}
}
7. Hashtable
典型的空间换时间,存储数据不能太多,但增删改查速度非常快。
特别注意:Hashtable是线程安全的,不需要配合锁使用。
{
Console.WriteLine("---------------------------07 Hashtable-----------------------------------");
Hashtable tableList = new Hashtable();
//存储
tableList.Add("", "马茹");
tableList[""] = "二胖";
//查询
foreach (DictionaryEntry item in tableList)
{
Console.WriteLine("key:{0},value:{1}", item.Key.ToString(), item.Value.ToString());
}
}
8. Dictionary<K,T>字典 (泛型的Hashtable)
增删改查速度非常快,可以用来代替实体只有id和另一个属性的时候,大幅度提升效率。
特别注意:Dictionary<K,T>不是线程安全,在多线程中需要配合锁机制来进行,如果不想使用锁,线程安全的字典为 ConcurrentDictionary。
{
Console.WriteLine("---------------------------08 Dictionary<K,T>字典-----------------------------------");
Dictionary<string, string> tableList = new Dictionary<string, string>();
//存储
tableList.Add("", "马茹");
tableList.Add("", "二胖");
tableList[""] = "三胖";
//查询
foreach (var item in tableList)
{
Console.WriteLine("key:{0},value:{1}", item.Key.ToString(), item.Value.ToString());
}
}
强调:
以上8种类型,除了Hashtable是线程安全,其余都不是,都需要配合lock锁来进行,或者采用 ConcurrentXXX来替代。
详细的请见:http://www.cnblogs.com/yaopengfei/p/8322016.html
二. 四大接口比较
1. IEnumerable
是最基本的一个接口,用于迭代使用,里面有GetEnumerator方法。
2. ICollection
继承了IEnumerable接口,主要用于集合,内部有Count属性表示个数,像ArrayList、List、LinkedList均实现了该接口。
3. IList
继承了IEnumerable 和 ICollection,实现IList接口的数据接口可以使用索引访问,表示在内存上是连续分配的,比如Array、List。
4. IQueryable
这里主要和IEnumerable接口进行对比。
Enumerable里实现方法的参数是Func委托,Queryable里实现的方法的参数是Expression表达式。
实现IQueryable和IEnumabler均为延迟加载,但二者的实现方式不同,前者为迭代器模式,参数为Func委托,后者为Expression表达式目录树实现。
三. yield关键字
1. yield必须出现在IEunmerable中
2. yield是迭代器的状态机,能做到延迟查询,使用的时候才查询,可以实现按序加载
3. 例子
测试一:在 “var data1 = y.yieldWay();”加一个断点,发现直接跳过,不能进入yieldWay方法中,而在“foreach (var item in data1)”加一个断点,第一次遍历的时候就进入了yieldWay方法中,说明了yield是延迟加载的,只有使用的时候才查询。
测试二:对yieldWay和commonWay获取的数据进行遍历,通过控制台发现前者是一个一个输出,而后者是先一次性获取完,一下全部输出来,证明了yield可以做到按需加载,可以在foreach中加一个限制,比如该数据不满足>100就不输出。
//********************************* 下面为对比普通返回值和使用yeild返回值的方法 ************************************************
/// <summary>
/// 含yield返回值的方法
/// </summary>
/// <returns></returns>
public IEnumerable<int> yieldWay()
{
for (int i = ; i < ; i++)
{
yield return this.Get(i);
}
}
/// <summary>
/// 普通方法
/// </summary>
/// <returns></returns>
public IEnumerable<int> commonWay()
{
int[] intArray = new int[];
for (int i = ; i < ; i++)
{
intArray[i] = this.Get(i);
}
return intArray;
}
/// <summary>
/// 一个获取数据的方法
/// </summary>
/// <param name="num"></param>
/// <returns></returns>
private int Get(int num)
{
Thread.Sleep();
return num * DateTime.Now.Second;
}
Console.WriteLine("-----------------------下面是调用yield方法-----------------------");
yieldDemo y = new yieldDemo();
var data1 = y.yieldWay();
foreach (var item in data1)
{
Console.WriteLine(item);
}
Console.WriteLine("-----------------------下面是调用普通方法-----------------------");
var data2 = y.commonWay();
foreach (var item in data2)
{
Console.WriteLine(item);
}
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字的更多相关文章
- ASP.NET MVC深入浅出系列(持续更新) ORM系列之Entity FrameWork详解(持续更新) 第十六节:语法总结(3)(C#6.0和C#7.0新语法) 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字 各种通讯连接方式 设计模式篇 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借
ASP.NET MVC深入浅出系列(持续更新) 一. ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态模 ...
- 【C#复习总结】探究各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字
前言 先普及一下线程安全和类型安全 线程安全: 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的 ...
- .NET面试题系列(五)数据结构(Array、List、Queue、Stack)及线程安全问题
常用数据结构的时间复杂度 如何选择数据结构 Array (T[]) 当元素的数量是固定的,并且需要使用下标时. Linked list (LinkedList<T>) 当元素需要能够在列表 ...
- libevent学习笔记(参考libevent深度剖析)
最近自学libevent事件驱动库,参考的资料为libevent2.2版本以及张亮提供的<Libevent源码深度剖析>, 参考资料: http://blog.csdn.net/spark ...
- 大众点评开源分布式监控平台 CAT 深度剖析
一.CAT介绍 CAT系统原型和理念来源于eBay的CAL的系统,CAT系统第一代设计者吴其敏在eBay工作长达十几年,对CAL系统有深刻的理解.CAT不仅增强了CAL系统核心模型,还添加了更丰富的报 ...
- js对象详解(JavaScript对象深度剖析,深度理解js对象)
js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕 ...
- 深度剖析HashMap的数据存储实现原理(看完必懂篇)
深度剖析HashMap的数据存储实现原理(看完必懂篇) 具体的原理分析可以参考一下两篇文章,有透彻的分析! 参考资料: 1. https://www.jianshu.com/p/17177c12f84 ...
- planning深度剖析
planning深度剖析 结合find命令过滤目录及文件名后缀: find /home/hadoop/nisj/automationDemand/ -type f -name '*.py'|xargs ...
- 3.3.4深度剖析ConcurrentLinkedQueue
队列.链表之类的数据结构及其常用.Java中,ArrayList和Vector都是使用数组作为其内部实现.两者最大的不同在于:Vector是线程安全的,而ArrayList不是.此外LinkedLis ...
随机推荐
- SQLServer之UNIQUE约束
UNIQUE约束添加规则 1.唯一约束确保表中的一列数据没有相同的值. 2.与主键约束类似,唯一约束也强制唯一性,但唯一约束用于非主键的一列或者多列的组合,且一个表可以定义多个唯一约束. 使用SSMS ...
- 【导航】Python常用资源(从新手到大牛)
[博客导航] [Python相关] 个人网站/博客/学习平台 中国大学MOOC :高校课程网上公开课学习平台,<Python语言程序设计>是我的入门课. Python123平台 :跟中国 ...
- Spring系列-SpringBoot 学习路径
学习spring boot 已经有很长一段时间,与其说学习,不如说是使用. 在过去的很长时间我一直奉行实用主义,任何技术我都是在应用中使用,很少是因为为了学习而学习. 当然,有那么几次心血来潮,去专门 ...
- web框架开发-Django用户认证组件
可以用认证组件做什么 针对session的缺陷, 跟新数据时,不跟新key键, 用户认证组件是删除后再重建 用户认证组件很多功能可以直接使用 利用用户认证表(auth_user,通过Django自己创 ...
- 1.3 Windows注册表
如何打开Windows注册表呢? 方法一:Win+R打开命令行,再输入regetdit,回车. 方法二:打开计算机,进入系统所在盘,进入Windows\System32文件夹,找到regedt32,双 ...
- day14- 面向对象基础(一)
今天开始写关于面向对象的内容,面向对象是编程思想中一大思想,由于日常使用中经常会用到,本次主要是对于我个人认为重点的基础知识进行整理,不会特别详细的书写. 1.面向过程与面向对象的区别 2.类 3.类 ...
- [LeetCode] 7. 整数反转
题目链接:https://leetcode-cn.com/problems/reverse-integer/ 题目描述: 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 ...
- .NET 开源项目 Anet 介绍
使用 Anet 有一段时间了,已经在我的个人网站(如 bookist.cc)投入使用,目前没有发现什么大问题,所以才敢写篇文章向大家介绍. GitHub 地址:https://github.com/a ...
- JS 面向对象 ~ 继承的7种方式
前言: 继承 是 OO 语言中的一个最为人津津乐道的概念.许多 OO 语言都支持两种继承方式:接口继承 和 实现继承.接口继承只继承方法签名,而实现继承则继承实际的方法.如前所述,由于函数没有签名,在 ...
- Winform数据库连接app.config文件配置
1.添加配置文件 新建一个winform应用程序,类似webfrom下有个web.config,winform下也有个App.config;不过 App.config不是自动生成的需要手动添加,鼠标右 ...