[技术相关]List、Dictionary转Dictionary的性能分析
1. 背景
我们经常有对List和Dictionary列表进行复制、转换等操作,在数据量较少时(几万以内)各种转换速度不会被觉察,但是数据量很大时(百万左右),各种转换方式的性能就会体现出来。
本文档将对列表转换效率进行测试,最终得出效率较高的方法,指导今后软件开发对技术的选择。另外,本文还将对列表转换过程中由另一线程修改列表数据时,是否会出现异常进行确认。
2013年5月16日星期四
2. 结论
1、在Dictionary转Dictionary过程中由另一线程修改列表数据时,会出现异常。
2、采用Dictionary.ToDictionary()的方式速度很慢,100万条需要249毫秒
3、采用Dictionary.Value.ToList的方式速度很快,100万条数据仅32毫秒;
4、List.ToDictionary的方式速度需要109毫秒;
3. 环境
1)开发环境采用VS2008,C#程序,手动编写代码实现。
2)测试列表中包含100万条数据。
4. 分析
4.1. 过程1:修改列表,是否对转换造成异常
1、方法:用两个线程,一个线程负责Dictionary转换,一个对列表进行修改。
结果:系统报错,确实会出现异常。
2、详细说明(详情参见下方源代码)
用线程函数TH_DicTest0()进行转换操作,用线程函数TH_DicTest1()进行列表内容修改操作。
4.2. 过程2:列表转换速度分析
1、方法1:采用Dictionary.ToDictionary()的方式,
结果:16:44:08 标识:[ToDic时间] 运行时间为:249; 运行次数:1
2、方法2:采用Dictionary.Value.ToList,然后再List.ToDictionary的方式进行转换;
结果:
1)Dictionary.Value.ToList的方式用时:
16:44:08 标识:[ToList时间] 运行时间为:32; 运行次数:1
2)List.ToDictionary的方式用时:
16:44:08 标识:[转Dic时间] 运行时间为:109; 运行次数:1
1 #region Dictionary测试 2 private MainThread _tt0 = new MainThread(); 3 private MainThread _tt1 = new MainThread(); 4 private Dictionary<int, DataTestItem> _dicTest = new Dictionary<int, DataTestItem>(); 5 private Dictionary<int, DataTestItem> _dicTest1; 6 private void button17_Click(object sender, EventArgs e) 7 { 8 Init_DicTest(); 9 10 _tt0.Add(TH_DicTest0, 1); 11 _tt1.Add(TH_DicTest1, 1); 12 13 //_tt1.Start(); 14 _tt0.Start(); 15 } 16 private void Init_DicTest() 17 { 18 DataTestItem item = null; 19 for (int i = 0; i < 1000000; i++ ) 20 { 21 item = new DataTestItem(); 22 item.a1 = i; 23 item.a2 = i + 1; 24 _dicTest.Add(item.a1, item); 25 } 26 } 27 private List<DataTestItem> _lstTest = null; 28 private void TH_DicTest0() 29 { 30 try 31 { 32 RunTimeScan.Instance().Begin("ToList时间"); 33 _dicTest1 = new Dictionary<int, DataTestItem>(); 34 _lstTest = _dicTest.Values.ToList(); 35 RunTimeScan.Instance().Stop("ToList时间"); 36 37 RunTimeScan.Instance().Begin("转Dic时间"); 38 foreach (DataTestItem item in _lstTest) 39 { 40 _dicTest1.Add(item.a1, item); 41 } 42 RunTimeScan.Instance().Stop("转Dic时间"); 43 44 RunTimeScan.Instance().Begin("ToDic时间"); 45 _dicTest1 = _dicTest.ToDictionary(p => p.Key, p => p.Value); 46 RunTimeScan.Instance().Stop("ToDic时间"); 47 48 AddTipMsg(RunTimeScan.Instance().GetRet("ToList时间")); 49 AddTipMsg(RunTimeScan.Instance().GetRet("转Dic时间")); 50 AddTipMsg(RunTimeScan.Instance().GetRet("ToDic时间")); 51 } 52 catch (System.Exception ex) 53 { 54 AddTipMsg(ex.Message + ex.StackTrace); 55 } 56 } 57 private void TH_DicTest1() 58 { 59 try 60 { 61 RunTimeScan.Instance().Begin("Add_100"); 62 63 DataTestItem item = null; 64 for (int i = 0; i < 100; i++) 65 { 66 item = new DataTestItem(); 67 item.a1 = _dicTest.Count() + i; 68 item.a2 = i + 1; 69 _dicTest.Add(item.a1, item); 70 Thread.Sleep(20); 71 } 72 73 RunTimeScan.Instance().Stop("Add_100"); 74 AddTipMsg(RunTimeScan.Instance().GetRet("Add_100")); 75 } 76 catch (System.Exception ex) 77 { 78 AddTipMsg(ex.Message + ex.StackTrace); 79 } 80 } 81 #endregion