List<T>与Dictionary<string,T>频繁检索的性能差距
2015-11-27 10:56
597 查看
一直对LINQ简洁高效的语法青睐有加,对于经常和资料库,SQL语法打交道的C#开发者来说,LINQ无疑是一个非常不错的选择,当要在List<T>(T为一个普通对象)集合中查找满足某些条件的某个对象时,写成 form t in T where t. Property1 == "A" && t. Property2== "B" …select t或者写成T.Where(t=>t. . Property1 == "A" && t. Property2== "B" …),是再自然不过的了。乍看之下,反正List<T>已被存在记忆体,无需顾忌反复查询所产生的连续成本,而且where条件也十分通俗易懂。但是当你需要频繁检索某个集合中的满足某些条件的对象时,比如需要求两个集合中的差集时,你有没有考虑过性能问题呢?最近的项目遇到频繁检索资料库,对比查询的多个对象的性能瓶颈问题,于是做了下面这个测试,下面我们来看一个对比测试:
View Code
随机构造一个容量为10万的List<T>集合和Dictionary<string,T>集合,产生一个随机数作为检索的“频率”,也就是在这10万个对象中要检索的次数(这里产生了1639个检索对象),执行结果让人大吃一惊,耗时相差尽然如此之大。
从测试结果来看,两者的效率天壤之别,而且随着检索集合的容量大小和检索频率成”正比”趋势: 使用LINQ Where检索,执行三次平均检索1600多次13秒左右;而Dictionary执行三次检索1600多次也不超过10ms! LINQ to Object的Where的查询不像数据库可以靠索引加速检索,当查询元素的对象很多,并且查询检索非常频繁时,可以考虑使用Dictionary<string, T>等做法取代Where条件检索,避免不必要的性能损失。
结论:依赖LINQ的Where查询在大量资料库中频繁检索数据是,很容易形成效率瓶颈。遇到这样的需求,可通过ToDictionary()简单转换成Dictionary,可以获得大幅度的性能提升。
有人质疑list 转成 dictionary 的时间开销,这里就把本测试的list 转成 dictionary 的时间开销也发出来,
鄙人能力有限,以上测试纯属个人知识点查缺补漏应用,不敢强加应用场景,以免误人子弟,若有不妥或者错误的地方,还望各位大神斧正。
public static class LinqOrDictioanry { public static string GetLinqSingle(List<Model> model, string id, string sbName) { return model.Single(o => o.Id == id && o.SbName == sbName).JuName; } public static string GetDictionaryValue(Dictionary<string, Model> dictionaryModel, string id, string sbName) { return dictionaryModel[string.Format("{0}\t{1}", id, sbName)].JuName; } }
[TestMethod] public void TestMethod1() { var model = new List<Model>(); const int count = 100000; var time = 3; var random = new Random(count); for (var i = 0; i < count; i++) { model.Add(new Model() { Id = Guid.NewGuid().ToString(), JuName = "JuName" + random.Next(0, 10000), SbName = "SbName" + random.Next(0, 10000), Dydj = "Dydj" + random.Next(0, 10000), ZhangChang = "ZhangChang" + random.Next(0, 10000), YcHang = "YcHang" + random.Next(0, 10000), Time = DateTime.Now, Total = random.Next(0, 10000) }); } var dictionary = model.ToDictionary(d => string.Format("{0}\t{1}", d.Id, d.SbName), d => d); var toModel = new List<Model>(); var tempCount = random.Next(500, 10000); for (var i = 0; i < tempCount; i++) { var sample = model[random.Next(model.Count)]; toModel.Add(new Model() { Id = sample.Id, SbName = sample.SbName }); } Console.WriteLine("Count={0}>{1}", model.Count, tempCount); for (var i = 0; i < time; i++) { Console.WriteLine("第 {0}次检索{1} 个对象", i, tempCount); var sw = new Stopwatch(); sw.Start(); for (var j = 0; j < tempCount; j++) { var model1 = toModel[j]; model1.JuName = LinqOrDictioanry.GetLinqSingle(model, model1.Id, model1.SbName); } sw.Stop(); Console.WriteLine("耗时 {0}ms", sw.ElapsedMilliseconds); Console.WriteLine("查看目标集合中最前面的数据,中间一点的数据,和最后一个数据看是否成功把数据检索出来?{0}, {1}, {2}", toModel[1].JuName, toModel[tempCount / 2].JuName, toModel[tempCount - 1].JuName); } Console.WriteLine(""); for (var i = 0; i < time; i++) { Console.WriteLine("第 {0}次检索{1}个对象", i, tempCount); var sw = new Stopwatch(); sw.Start(); for (var j = 0; j < tempCount; j++) { var model1 = toModel[j]; model1.JuName = LinqOrDictioanry.GetDictionaryValue(dictionary, model1.Id, model1.SbName); } sw.Stop(); Console.WriteLine("耗时 {0}ms", sw.ElapsedMilliseconds); Console.WriteLine("查看目标集合中最前面的数据,中间一点的数据,和最后一个数据看是否成功把数据检索出来?{0} ,{1} ,{2}", toModel[1].JuName, toModel[tempCount / 2].JuName, toModel[tempCount - 1].JuName); } }
View Code
随机构造一个容量为10万的List<T>集合和Dictionary<string,T>集合,产生一个随机数作为检索的“频率”,也就是在这10万个对象中要检索的次数(这里产生了1639个检索对象),执行结果让人大吃一惊,耗时相差尽然如此之大。
从测试结果来看,两者的效率天壤之别,而且随着检索集合的容量大小和检索频率成”正比”趋势: 使用LINQ Where检索,执行三次平均检索1600多次13秒左右;而Dictionary执行三次检索1600多次也不超过10ms! LINQ to Object的Where的查询不像数据库可以靠索引加速检索,当查询元素的对象很多,并且查询检索非常频繁时,可以考虑使用Dictionary<string, T>等做法取代Where条件检索,避免不必要的性能损失。
结论:依赖LINQ的Where查询在大量资料库中频繁检索数据是,很容易形成效率瓶颈。遇到这样的需求,可通过ToDictionary()简单转换成Dictionary,可以获得大幅度的性能提升。
有人质疑list 转成 dictionary 的时间开销,这里就把本测试的list 转成 dictionary 的时间开销也发出来,
鄙人能力有限,以上测试纯属个人知识点查缺补漏应用,不敢强加应用场景,以免误人子弟,若有不妥或者错误的地方,还望各位大神斧正。
相关文章推荐
- 逻辑架构、体系架构、整体架构、功能架构
- stand up meeting 11/26/2015
- [ActionScript 3.0] Away3D 天空盒(skybox)例子2
- Docker 监控实战
- IOS静态库制作
- 黑马程序员——JAVA基础——网络编程
- Ubuntu安装pycharm
- 五个免费UML建模工具推荐
- android客户端与服务器端交互 如何保持session
- 一、Camera显示之app实现简单camera
- kali攻防第5章 内网称霸之HTTPS账号密码获取
- 随想08:待杀的猪
- A SPI class of type org.apache.lucene.codecs.PostingsFormat with name 'Lucene40' does not exist.
- Objective-C RunTime机制(1)
- chattr和lsattr区别
- MyEclipse界面窗口布局恢复
- Mysql分库分表方案
- Docker 监控实战
- mysql bin-log日志过大造成磁盘爆满问题解决。
- android数据库中读写cookie