.Net 3.5环境下常用数组性能测试

这件事情似乎很无聊,但是没人做,我来做下苦力吧。

以下是一些简单的测试。单位以ms计算。注意里面用到循环的数量有些事1W,有些是100W。

这些记录可以作为编程过程中的一些参考。

测试平台:

奔腾1.6G 双核CPU
1G内存
vs2008 调试环境测试。


一、ArrayList (100W,1W)

            Stopwatch timer = new Stopwatch();
            timer.Start();

            System.Collections.ArrayList al 
= new System.Collections.ArrayList();

            
for (int i = 0; i < 1000000; i++)
            {
                al.Add(i);
            }

            timer.Stop();

            Console.Write(timer.ElapsedMilliseconds.ToString() 
+ "\t");

            Stopwatch timer1 
= new Stopwatch();
            timer1.Start();

            
for (int i = 0; i < 10000; i++)
            {
                al.Contains(i);
            }

            timer1.Stop();

            Console.WriteLine(timer1.ElapsedMilliseconds.ToString());

98    775
160    891
107    773
193    769


二、Hashtable (100W,1W)

            Stopwatch timer = new Stopwatch();
            timer.Start();

            System.Collections.Hashtable ht 
= new System.Collections.Hashtable();

            
for (int i = 0; i < 1000000; i++)
            {
                ht.Add(i, i);
            }

            timer.Stop();

            Console.Write(timer.ElapsedMilliseconds.ToString() 
+ "\t");

            Stopwatch timer1 
= new Stopwatch();
            timer1.Start();

            
for (int i = 0; i < 10000; i++)
            {
                ht.ContainsKey(i);
            }

            timer1.Stop();

            Console.WriteLine(timer1.ElapsedMilliseconds.ToString());
        }

375 0
673 0
540 0
495 0

把timer1提高到100万(Hashtable (100W,100W))

389 139
616 277
516 140
610 277

三、HashSet (100W,100W)

Stopwatch timer = new Stopwatch();
            timer.Start();

            System.Collections.Generic.HashSet
<int> ht = new System.Collections.Generic.HashSet<int>();

            
for (int i = 0; i < 1000000; i++)
            {
                ht.Add(i);
            }

            timer.Stop();

            Console.Write(timer.ElapsedMilliseconds.ToString() 
+ "\t");

            Stopwatch timer1 
= new Stopwatch();
            timer1.Start();

            
for (int i = 0; i < 1000000; i++)
            {
                ht.Contains(i);
            }

            timer1.Stop();

            Console.WriteLine(timer1.ElapsedMilliseconds.ToString());



89 32
79 32
79 32
117 31

四、List (100W,1W)

            Stopwatch timer = new Stopwatch();
            timer.Start();

            System.Collections.Generic.List
<int> ht = new System.Collections.Generic.List<int>();

            
for (int i = 0; i < 1000000; i++)
            {
                ht.Add(i);
            }

            timer.Stop();

            Console.Write(timer.ElapsedMilliseconds.ToString() 
+ "\t");

            Stopwatch timer1 
= new Stopwatch();
            timer1.Start();

            
for (int i = 0; i < 10000; i++)
            {
                ht.Contains(i);
            }

            timer1.Stop();

            Console.WriteLine(timer1.ElapsedMilliseconds.ToString());


16 379
19 392
18 403
18 392

把List<int>换成List<object>

96 945
157 1033
106 909
193 910

换成string,i.ToString()

496 1238
531 1190
572 1246
536 1258

五、Dictionary (100W,100W)

            Stopwatch timer = new Stopwatch();
            timer.Start();

            System.Collections.Generic.Dictionary
<intint> ht = new System.Collections.Generic.Dictionary<intint>();

            
for (int i = 0; i < 1000000; i++)
            {
                ht.Add(i, i);
            }

            timer.Stop();

            Console.Write(timer.ElapsedMilliseconds.ToString() 
+ "\t");

            Stopwatch timer1 
= new Stopwatch();
            timer1.Start();

            
for (int i = 0; i < 1000000; i++)
            {
                ht.ContainsKey(i);
            }

            timer1.Stop();

            Console.WriteLine(timer1.ElapsedMilliseconds.ToString());

113 35
125 34
124 34
126 34


六、Dictionary Linq查询 (100W,100W)

用个Linq试试
            Stopwatch timer = new Stopwatch();
            timer.Start();

            System.Collections.Generic.Dictionary
<intint> ht = new System.Collections.Generic.Dictionary<intint>();

            
for (int i = 0; i < 1000000; i++)
            {
                ht.Add(i, i);
            }

            timer.Stop();

            Console.Write(timer.ElapsedMilliseconds.ToString() 
+ "\t");

            Stopwatch timer1 
= new Stopwatch();
            timer1.Start();

            
for (int i = 0; i < 1000000; i++)
            {
                ht.Where(c 
=> c.Key == i);
            }

            timer1.Stop();

            Console.WriteLine(timer1.ElapsedMilliseconds.ToString());


112 177
107 78
125 70
107 82

结论:
1、如果是使用缓存的话,那么3.5带来的单泛型集合的HashSet可以替代List了。虽然载入速度慢一点,但是查询速度要比List泛型快很多。要注意到,上述测试List的查询时万级的,而HashSet是百万级

2、Dictionary泛型可以替换掉Hashtable了,虽然如果在字符或者object类型下可能会没这么明显。但是在数字类型的匹配上,Dictionary比Hashtable大概快了2倍,而这个开销估计是Hashtable的装箱造成的。

3、Linq还是要慢一些。

by yurow. http://www.cnblogs.com/birdshover/

posted on 2008-03-19 23:31 Birdshover 阅读(2782) 评论(21)  编辑 收藏 所属分类: .Net language and other

评论

#1楼  2008-03-19 23:42 Tristan(Guozhijian)      

good works!   回复  引用  查看    

#2楼  2008-03-19 23:44 i am threem0126 [未注册用户]

好文,找机会实用体验看看!   回复  引用    

#3楼  2008-03-20 01:29 yzlhccdec      

HashSet不能重复但是List可以   回复  引用  查看    

#4楼 [楼主] 2008-03-20 02:03 BirdsHover      

@yzlhccdec
大多数应用还是没有重复的吧   回复  引用  查看    

#5楼  2008-03-20 08:19 专研.NET      

好(本山语!)   回复  引用  查看    

#6楼  2008-03-20 08:38 戏水      

楼主是实干家。 这些数据很不错。   回复  引用  查看    

#7楼  2008-03-20 08:51 韩 [未注册用户]

牛的,我也待会测试一下   回复  引用    

#8楼  2008-03-20 09:40 StillWartersRunDeep      

lz 辛苦   回复  引用  查看    

#9楼  2008-03-20 11:01 A.Z! [未注册用户]

你用linq干什么啊...   回复  引用    

#10楼 [楼主] 2008-03-20 11:04 BirdsHover      

@A.Z!
用linq只是看下Linq对数组的操作效率,这里不够详细,有兴趣的朋友可以自己去做   回复  引用  查看    

#11楼  2008-03-20 11:05 diviner [未注册用户]

性能是一点一滴的,知此知彼,从小的做起.
这种比较很好.   回复  引用    

#12楼  2008-03-20 11:08 diviner [未注册用户]

可以试试放引用类别的数据进行,再比较一下.   回复  引用    

#13楼  2008-03-20 13:26 Angel Lucifer      

1.HashSet<T>和List<T>是不同用途的数据结构,解决的场景也不尽相同,不存在谁被谁取代的问题。

比如List<T>可以排序,HashSet<T>可以吗?排序之后,List<T>的BinarySearch查询速度也相当的快速。
List<T>可以通过索引来查找数据,HashSet<T>可以吗?在知道其索引的情况下,List<T>的查找速度比HashSet<T>快得多,究其原因在于数组在内存的访问速度比其他数据结构都要快。

此外,如果仅在末端插入数据,List<T>的插入速度可以跟LinkedList<T>相媲美,比方说,如果你知道你大概要插入多少数据,完全可以预先分配内存,如楼主的情况则可以 new List<int>(1000000) ,这样就可以省去相当多的数组再分配,重新复制原数组内容的开销。当然,HashSet<T>也可以采取类似措施,但是比List<T>要考虑的方面多一些罢了。上面有位老兄也指出一个关键方面,就是List<T>的元素可以重复,而HashSet<T>却是不能重复的。

2.Dictionary<T>的确应该替代Hashtable,撇开泛型和装箱等原因,其内部采用的解决collision方案也要好于Hashtable。

采用何种数据结构,完全是看场景的需求如何,一概而论完全不足取。
  回复  引用  查看    

#14楼  2008-03-20 14:54 George Shen [未注册用户]

1W的测试偏向于ArrayList,List<T>,因为顺序查找时前1W个更容易被找到,我相信要是List哪个测试改成:
for (int i = 0; i < 1000000; i++){ht.Contains(0);}的话速度肯定还是很快。可是如果是找
for (int i = 0; i < 10000; i++){ht.Contains(999999);}的话肯定很慢。

而对于采用Hash存储的情况,不同的Hash算法,对于不同的采样分布,效率肯定也是不同的,完全可以某些数据HashTable快,而Dictionary慢的(如果HashTable和Dictionary的Hash算法的确不同的话)   回复  引用    

#15楼  2008-03-20 16:09 Brilliance_DaveLin      

采用何种数据结构,完全是看场景的需求如何,一概而论完全不足取。   回复  引用  查看    

#16楼 [楼主] 2008-03-20 18:01 BirdsHover      

我最近要用的的应用是分词的,这里面的测试都是大数据量运用的。我测试了下,换成Dictionary和HashSet后,速度已经提高了好几倍,再摒弃了一些算法后,现在基本上速度是以前的30倍以上   回复  引用  查看    

#17楼  2008-03-21 13:49 Jeffrey Zhao      

HashSet的查询自然要比List快,List又没有索引,Contains方法用的是遍历,O(N)的操作,HashSet,Dictionary用的是O(1)的操作。
至于LINQ慢,主要是一个Expression Tree的解析操作,如果可以避免的确应该不用。   回复  引用  查看    

#18楼  2008-03-22 10:47 毁于随      

@Jeffrey Zhao
Angel Lucifer说List可以用索引,老赵说没有索引,到底谁对?   回复  引用  查看    

#19楼  2008-03-22 11:52 Angel Lucifer      

@毁于随

请注意措辞,呵呵。

List没有索引,它只是在内部维护一个数组而已。
但可以通过IndexOf等之类的方法得到它数组的索引,通过这个索引来访问数组。

要注意的是List允许有重复值,IndexOf查找到的索引只是查到该值在数组内第一次出现的位置。使用的时候要小心。知道索引之后,时间复杂度就成了O(1),比HashSet的O(1)要快的多。但是在之前,时间复杂度是O(N)。
所以说,要分场合。:-)   回复  引用  查看    

#20楼  2008-03-22 15:07 毁于随      

--引用--------------------------------------------------
Angel Lucifer: @毁于随

请注意措辞,呵呵。

List没有索引,它只是在内部维护一个数组而已。
但可以通过IndexOf等之类的方法得到它数组的索引,通过这个索引来访问数组。

要注意的是List允许有重复值,IndexOf查找到的索引只是查到该值在数组内第一次出现的位置。使用的时候要小心。知道索引之后,时间复杂度就成了O(1),比HashSet的O(1)要快的多。但是在之前,时间复杂度是O(N)。
所以说,要分场合。:-)
--------------------------------------------------------
知道索引以后就O(1)了?List不会自动维护这个吧?需要自己用变量记录?你上面说可以通过索引来查找数据,我还以为它在内部建立了索引,原来你的意思是可以通过IndexOf来操作.....晕了.   回复  引用  查看    

#21楼  2008-03-22 16:17 Angel Lucifer      

@毁于随
知道索引之后,查找的时间复杂度不是O(1)是多少?

List内部只维护一个数组,所以它不会维护索引。如果需要索引值,只能自己计算。
HashSet内部则维护两个数组,此外还有一个链表。
通过Key的HashCode来查找,实际上就是计算内部数组索引的过程。

再次重申,采用何种数据结构,完全是看场景的需求如何,一概而论完全不足取。List和HashSet压根就不应该拿来作比较。   回复  引用  查看    

导航

公告

网名: yurow birdshover
       无术 夕阳轨迹 等
本名: 谢平
籍贯: 江苏溧阳
位置: 上海
职业: C# & 打字
联系方式: 19999351(QQ)
 MSN.gif
更新了8个小时,终于把compass下载下来了 ==@ 7-24 12:26
<2008年3月>
2425262728291
2345678
9101112131415
16171819202122
23242526272829
303112345

统计

与我联系

常用链接

留言簿

我管理的小组

我参与的团队

我的标签

随笔分类(78)

文章分类(19)

收藏夹(1)

关注的博客

搜索

积分与排名

最新评论