您的位置:首页 > 其它

提高程序性能的小细节--以后会不断添加小技巧

2013-06-22 11:12 204 查看
第一大类:简化循环

小到一个内网扫描工具,大到一个GIS系统,大大小小的软件系统中都会用到很多循环,计算机能够比人脑显得有能力的最重要的一点就是:计算机软件可以任劳任怨的去执行枯燥的类似遍历的循环。所以任何写软件的编程人员都会涉及到设计循环结构的问题。一个好的循环结构能够在解决相同问题的同时节省更多的时间或空间。很多人会自然的想到各种排序、查找算法的设计问题,因为相关的大神级文档遍布网络,本文就不赘述,只是总结一些代码细节的内容,旨在阐述“代码方案”的决策对于程序性能影响。

案例1:不要把已知特例放到循环里面去判断

有下列代码,源码的作者为了简化代码的书写,将一个已知特列的判断放到了循环中。此循环是一个经典的遍历循环,for中语句的执行次数为framePosition.Count()次。

for (int i = 0; i < framePosition.Count(); i++)
{

//加入X轴方向的匀速关键帧

LinearDoubleKeyFrame keyFrame = new LinearDoubleKeyFrame();

keyFrame.Value = i == 0 ? Canvas.GetLeft(player) : framePosition[i].X; //平滑衔接动画

keyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(cost * i));

keyFramesAnimationX.KeyFrames.Add(keyFrame);

//加入X轴方向的匀速关键帧

keyFrame = new LinearDoubleKeyFrame();

keyFrame.Value = i == 0 ? Canvas.GetTop(player) : framePosition[i].Y;

keyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(cost * i));

keyFramesAnimationY.KeyFrames.Add(keyFrame);

}


如行7、17所示,i == 0 ? Canvas.GetTop(player) : framePosition[i].Y;为三目运算符,相当于以下代码:

if( i == 0 )
{
 Canvas.GetTop(player) :
}else
{
 framePosition[i].Y;
}


程序这样的写的结果是,无论framePosition.Count()的值为1还是为N,行7、17的代码都会执行,但是从业务层面分析,“Canvas.GetTop(player) ”这句代码只需要在i==0时执行才是合理的,也就是说当0<framePosition.Count()<n时,所有的if判断都是没有意义的。经过这样的分析,可以将i==0的条件作为一个特列来处理,让循环从1开始,这样虽然多写了几行代码,但是会令代码得到很好的性能改善,何乐而不为呢?

总结:尽可能的减少循环里面的已知特例判断。

案例2 别忘了关键字“break”

int result=-1;
for(int i=0;i<count,i++)
{
  
  
if(count[i]==X)
  
result=count[i];
}


上面段代码演示了一个经典的遍历查找算法,代码最优情况下运行1次,最坏情况下运行count次,不过我说的是设计思路,设计时我们是这样想的,然而实际这段代码每次查找都会执行count次。我们有时候在工作中,繁忙的任务和逼人的进度往往会使在小公司工作的我们只关心代码是否能够正确的安装设计逻辑去执行,而疏忽了某些能提高性能的细节。 上面这段代码,如果集合中包含超出满足条件的结果,肯定能被找出,但是效率确实低下的。尤其是在有序队列中查找的时候(当然应该是一2分,而有时候调用者并不知道数据已经被拍序),次算法效率低下的几率更高。 只需添加一句break语句,就这么简单,便能提高效率。

int result=-1;
for(int i=0;i<count,i++)
{  
if(count[i]==X)
{
  result=count[i];
break;
}
}


[b]案例3 循环中的判断语句[/b]

假设有这样的语句:

Class MyDataRowCommunicating

{

 public byte Address_Hight;

public   byte Address_Low;

....

}


其中Address表示设备的地址,是一个16位的无符号整形值,分开存在Address_Hight和Address_Low里面(这种方式在通信类程序里面常常用到)。

在通信事物处理层常常会见到以下类似代码,用于比对“设备返回信息中包含的设备自身的地址”和“系统存储的会话列表中的设备地址”

List<MyDataRowCommunicating> myList= new List<MyDataRowCommunicating>();

....

byte Address_Hight_FromHW=GetAddressHight();

byte Address_Low_FromHW=GetAddressLow();

for(int i=0;i<myList.count;i++)

{

//我们会不加思索的这样来写这个判断语句

 

 if(Address_Hight_FromHW==myList[i].Address_Hight

&&Address_Low_FromHW==myList[i].Address_Low)

  {

    ....

  }

}


但是实时上设备的地址一般是从1开始递增的,一般很少有设备用到超过255以上的地址,所以地址的高位一般都为0,而我们知道在逻辑与运算中,if(X1&&X2)这样的语句,总是会先检测X1是否为ture,然后再检测X2是否为ture,如果都为ture方可进入if的内部。如果X1为ture的概率远大于X1位ture的几率,那么把X2写在前面会更合适一些。对应到本例应该写为if(X2&&X1)更为合适

if(Address_Low_FromHW==myList[i].Address_

&&LowAddress_Hight_FromHW==myList[i].Address_Hight)

而如果使用X1||X2逻辑或计算时,应该把为ture几率大的表达式放在最前面,这样可以减少代码检测的次数,从而提高性能。

[b]案例4 循环每次递增2次的写法[/b]

[b]下面的代码是要生成一行两列的html代码:[/b]

for (int LCount = 0; LCount < XNList.Count; LCount++)
{
        //i执行的内容
img_src = XNList[LCount].Attributes["textStr"].Value;
href = XNList[LCount].Attributes["href"].Value;
templateBuilder.Append("<a href=\"" + href + "\" style=\"border:hidden\">" + img_src + "</a>");
     //i加一
LCount++;
        //i+1后执行的内容
img_src = XNList[LCount].Attributes["textStr"].Value;
href = XNList[LCount].Attributes["href"].Value;
templateBuilder.Append("<a href=\"" + href + "\" style=\"border:hidden\">" + img_src + "</a></br>");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: