项目经验总结(三)

 

哪种方式查询泛型集合性能上最佳

这篇文章我来分析下对于泛型集合,采取不同的查询方式在性能上会有什么样的影响?

    这里有一个城市简单信息的实体类:

代码
class  CityInfo
    {
        
public   int  CityID
        {
            
get ;
            
set ;
        }
        
public   string  CityName
        {
            
get ;
            
set ;
        }
        
public   string  CityNameEn
        {
            
get ;
            
set ;
        }
        
public   string  CityAddress 
        { 
            
get
            
set ;
        }
    }

 

     我们构造一个特别大的城市泛型类:

代码
             int  i  =   100000 ;
            Random m 
=   new  Random();
            List
< CityInfo >  list  =   new  List < CityInfo > ();
            
for  ( int  j  =   0 ; j  <  i; j ++ )
            {
                CityInfo info 
=   new  CityInfo();
                info.CityID 
=  j;
                info.CityAddress 
=   " aaaaaa "   +  j.ToString();
                info.CityName 
=   " 城市中文名称 "   +  j.ToString();
                info.CityNameEn 
=   " 城市英文名称 "   +  j.ToString();
                list.Add(info);
            }

 

     根据城市ID查询某个城市的具体信息:
     方法一:foreach:

代码
         static  CityInfo GetCityInfoByForeach(List < CityInfo >  list,  int  CityID)
        {
            CityInfo info 
=   new  CityInfo();
            
foreach  (var item  in  list)
            {
                
if  (item.CityID  ==  CityID)
                {
                    info 
=  item;
                    breake;
                }
            }
            
return  info;
        }

 

      方法二:for循环:

代码
         static  CityInfo GetCityInfoByFor(List < CityInfo >  list,  int  CityID)
        {
            CityInfo info 
=   new  CityInfo();
            
for  ( int  i  =   0 ; i  <  list.Count;i  ++  )
            {
                
if  (list[i].CityID  ==  CityID)
                {
                    info 
=  list [i];
                    breake;

                 }
            }
            
return  info;
        }

 

     方法三:Linq查询:

代码
         static  CityInfo GetCityInfoByLinq(List < CityInfo >  list, int  CityID)
        {
            CityInfo info 
=   new  CityInfo();
            info 
=  list.Where(p  =>  p.CityID  ==  CityID).FirstOrDefault();
            
return  info;
        }

 

      然后随机产生一个城市ID,分别针对上面三种方式调用500次,这里何用老赵的CodeTimer来显示信息,执行结果如下:

 

代码
       CodeTimer.Time( " GetCityInfoByForeach " 500 , ()  =>  GetCityInfoByForeach(list, m.Next(i  -   1 )));
       CodeTimer.Time(
" GetCityInfoByFor " 500 , ()  =>  GetCityInfoByFor(list, m.Next(i  -   1 )));
       CodeTimer.Time(
" GetCityInfoByLinq " 500 , ()  =>  GetCityInfoByLinq(list, m.Next(i  -   1 )));

 

      项目经验总结(三)

 

       性能从高到低表现为:for,foreach,linq,仔细查看三种方法生成IL代码,有一定的区别:
       1:foreach方法在查询数据时,依赖了Enumerator ,它的特点是不能像对于数组一样使用索引,而只能将当前项指针移动到集合的第一个或下一个元素,这是它性能不是最优的主要问题所在。在这种方式中还有一个重要点就是在查询每个元素时都会有try finally块,这也是需要消耗部分性能的。

代码
  . try
  {
    IL_000d:  br.s       IL_0022
    IL_000f:  ldloca.s   CS$
5 $ 0000
    IL_0011:  call       instance 
! 0  valuetype [mscorlib]System.Collections.Generic.List` 1 / Enumerator < class  ConsoleApplication1.CityInfo > ::get_Current()
    IL_0016:  stloc.
1
    IL_0017:  ldloc.
1
    IL_0018:  callvirt   instance int32 ConsoleApplication1.CityInfo::get_CityID()
    IL_001d:  ldarg.
1
    IL_001e:  bne.un.s   IL_0022
    IL_0020:  ldloc.
1
    IL_0021:  stloc.
0
    IL_0022:  ldloca.s   CS$
5 $ 0000
    IL_0024:  call       instance 
bool  valuetype [mscorlib]System.Collections.Generic.List` 1 / Enumerator < class  ConsoleApplication1.CityInfo > ::MoveNext()
    IL_0029:  brtrue.s   IL_000f
    IL_002b:  leave.s    IL_003b
  }  
//  end .try
   finally
  {
    IL_002d:  ldloca.s   CS$
5 $ 0000
    IL_002f:  constrained. valuetype [mscorlib]System.Collections.Generic.List`
1 / Enumerator < class  ConsoleApplication1.CityInfo >
    IL_0035:  callvirt   instance 
void  [mscorlib]System.IDisposable::Dispose()
    IL_003a:  endfinally
  }  
//  end handler

 

      2:for方法在查询数据时,System.Collections.Generic.List`1<class ConsoleApplication1.CityInfo>::get_Item(int32),比起foreach少了try的处理,最重要的是能够使用索引访问元素。

      3:linq方式性能最差。

 

      非常感谢各位朋友的指点,特别是代码中忘记加break,现在是修改代码后的测试结果:结果和上面一样。

      项目经验总结(三)

 

      本篇文章的测试代码

 

      总结:泛型集合如果数据量大,最好采用for循环查询,数据量少的话,用linq方式最佳,代码优雅且简洁。

      题外话:其实针对这种泛型集合查询,如果想优化性能,最好不要存储成泛型集合,采用Dictionary或者是hashtable效果更佳。

 

你可能感兴趣的:(总结)