其实大多数的编译器本身就能提供一些简单的优化,比如gcc就能通过使用 -O2 或者 -O3 的选项来优化程序。但编译器的优化始终也是有限,因为它必须小心翼翼保证优化过程不对程序的功能有改动。故而程序员本身应该对程序有优化意识。在我看来,这也是应该有的一种良好的编程习惯。

  几种比较简单的优化措施:

  1.代码移动

  将要执行多次(比如在循环中)但计算结果不会改变的计算,移动到代码前面不会多次求值的部分。举一个比较极端的例子:

/* convert string to lowercase: slow*/
void lower( char *s ){
int i;
for( i = ;i < strlen(s);i++ )
if( s[i] >= 'A' && s[i] <= 'Z' )
s[i] -= ( 'A' - 'a');

}

因为C语言的字符串是以null结尾的,函数strlen也必须一步一步得检查这个序列,直到遇到null字符。那么假象一下,如果字符串s是一个很长的字符串,那么这个函数自然会造成许多不必要的开销!!
故而在循环体内,要注意将计算结果不改变的计算移动到前面避免多次重复计算。

  优化代码:

/* convert string to lowercase: faster*/
void lower( char *s ){
int i;
int len = strlen(s);
for( i = 0;i < len;i++ )
if( s[i] >= 'A' && s[i] <= 'Z' )
s[i] -= ( 'A' - 'a'); }

  2.消除不必要的存储器引用

  在C语言中用指针变量读写是用CPU寄存器间接寻址然后从内存中读写,而使用函数内部的局部变量,则是使用CPU中的通用寄存器。而主存读写和CPU内部通用寄存器的寻址的速度相差数十倍的。举一个小例子

for( i = 0;i < len;i++ ){
*dest = *dest + data[i];
}

这个循环体每次都会从主存中读写,优化如下:

int acc;
for( i = 0;i < len;i++ ){
acc = acc + data[i];
}
*dest = acc;

这样就会使那个指针只写入一次,而acc变量在cpu的执行过程中是使用cpu内部通用寄存器读写,故而能加快速度。

  3.循环展开

  循环展开,顾名思义就是将一次一步的迭代循环展开成一次两步或更多,减少迭代次数。循环展开从两个方面改善程序的性能,首先,它减少了不直接有助于程序结果的操作的数量,比如循环索引计算和条件分支。其次,它提供了一些方法,可以进一步变化代码,减少计算中关键路径上的操作数量。比较如下两个函数,第一个为常规循环,第二个为循环展开函数,

//normal function to add all element of v
void combine1( vec_ptr v,data_t *dest ){
int i = ;
long int length = vec_length( v );
   data_t *data = get_vec_start( v );
   data_t acc = IDENT;
for( i = ;i < length;i++ ){
acc = acc + data[i];
}
*dest = acc;
}
//unroll loop by 2
void combine2( vec_ptr v, data_t *dest ){
int i;
long int length = vec_length( v );
loing int limit = length -1;
data_t *data = get_vec_start( v );
data_t acc = IDENT; for( i = 0;i < limit;i += 2 ){
acc = ( acc + data[i] ) + data[i+1];
} for( ;i < length;i++ ){
acc = acc + data[i];
} *dest = acc;
}

第二个函数将循环展开,并在最后检查会不会遗漏。减少了一些关键步骤,故而优化了程序。

  4.提高并行性

  在cpu中,程序被翻译成汇编指令,但却并不是一条一条指令按顺序执行的,而是流水线并发执行的,即多条不相关指令共同执行。这是cpu的机器特性,而我们要做的,就是多多利用这种机器特性。

  让我们来分析程序的combine2中的核心循环内部语句:acc = ( acc + data[i] ) + data[i+1];在这个循环中,data[i+1]的计算必须放在( acc + data[i] )之后,因为它们是相互关联的,这明显是不利于程序的并行操作,改进如下。

//unroll loop by 2,2-way parallelism
void combine3( vec_ptr v, data_t *dest ){
int i;
long int length = vec_length( v );
loing int limit = length -1;
data_t *data = get_vec_start( v );
data_t acc0 = IDENT;
data_t acc1 = IDENT; for( i = 0;i < limit;i += 2 ){
acc0 = acc0 + data[i];
acc1 = acc1 + data[i+1];
} for( ;i < length;i++ ){
acc0 = acc0 + data[i];
} *dest = acc0 + acc1;
}

这段代码将acc拆分成acc0和acc1,使程序得以并发同时计算,最后再将两组结果想加,提高程序性能。

代码优化通常都会带来可读性的降低,如何取舍应该好好考虑清楚,必要时刻,或许应该多加一些注释说明。

以C语言为例的程序性能优化 --《深入理解计算机系统》第五章读书笔记的更多相关文章

  1. [JAVA] java程序性能优化

    一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...

  2. iOS程序性能优化

    iOS程序性能优化 一.初级 使用ARC进行内存管理 在iOS5发布的ARC,它解决了最常见的内存泄露问题.但是值得注意的是,ARC并不能避免所有的内存泄露.使用ARC之后,工程中可能还会有内存泄露, ...

  3. iOS 程序性能优化

    前言 转载自:http://www.samirchen.com/ios-performance-optimization/ 程序性能优化不应该是一件放在功能完成之后的事,对性能的概念应该从我们一开始写 ...

  4. [转]C#程序性能优化

    C#程序性能优化 1.显式注册的EvenHandler要显式注销以避免内存泄漏 将一个成员方法注册到某个对象的事件会造成后者持有前者的引用.在事件注销之前,前者不会被垃圾回收.   private v ...

  5. Java程序性能优化之性能概述

    性能的基本概念 一).什么叫程序的性能? 程序运行所需的内存和时间. 二).性能的表现形式: 1).执行速度: 程序的反应是否迅速,响应时间是否足够短. 2).启动时间:程序从运行到可以处理正常业务所 ...

  6. [深入浅出Cocoa]iOS程序性能优化

    本文转载至 http://blog.csdn.net/kesalin/article/details/8762032 [深入浅出Cocoa]iOS程序性能优化 罗朝辉 (http://blog.csd ...

  7. C++ 应用程序性能优化

    C++ 应用程序性能优化 eryar@163.com 1. Introduction 对于几何造型内核OpenCASCADE,由于会涉及到大量的数值算法,如矩阵相关计算,微积分,Newton迭代法解方 ...

  8. Java程序性能优化技巧

    Java程序性能优化技巧 多线程.集合.网络编程.内存优化.缓冲..spring.设计模式.软件工程.编程思想 1.生成对象时,合理分配空间和大小new ArrayList(100); 2.优化for ...

  9. 《Java程序性能优化:让你的Java程序更快、更稳定》

    Java程序性能优化:让你的Java程序更快.更稳定, 卓越网更便宜,不错的书吧

随机推荐

  1. JAVA基础-File类

    一.File类概述 File类是文件和目录路径名的抽象表示形式.File类可以理解为一个文件路径或者文件夹路径的JAVA表现形式,而路径又可以分为绝对路径(是一个固定路径,从盘符开始),相对路径(相对 ...

  2. [bzoj1227] [SDOI2009]虔诚的墓主人

    终于填上了这个万年巨坑....从初二的时候就听说过这题...然后一直不敢写QAQ 现在感觉也不是很烦(然而我还是写麻烦了 离散化一波,预处理出组合数什么的.. 要维护对于当前行,每列上方和下方节点凑出 ...

  3. BZOJ1758: [Wc2010]重建计划(01分数规划+点分治+单调队列)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1758 01分数规划,所以我们对每个重心进行二分.于是问题转化为Σw[e]-mid>=0, ...

  4. os系统

    任务延时函数OSTimeDly 功能:调用该函数的任务将自己延时一段时间并执行一次任务调度,一旦规定的延时时间完成或有其它的任务通过调用OSTimeDlyResume()取消了延时,调用OSTimeD ...

  5. C#的改进特性

    1.初始器 当你新建一个对象实例的时候,是否遇到下面这种情况: class a = new class(); a.item1 = "; a.item2 = "; 或者写一个构造函数 ...

  6. win7 64位安装redis 及Redis Desktop Manager使用(转载的)

    写基于dapper的一套自动化程序,看到 mgravell的另一个项目,StackExchange.Redis,之前在.NET上用过一段时间Redis,不过一直是其它的驱动开发包,这个根据作者介绍,是 ...

  7. jquery实现上下滑动选择

    $('.rightShow').on('mousewheel', function(ev) { var dir = ev.originalEvent.wheelDelta if(dir == 120) ...

  8. ZipKin的原理的介绍

    结构概述       跟踪器(Tracers)存在在你的应用程序中生存,记录时间和关于操作的元数据.他们经常使用库,因此他们的使用对用户是透明的.例如,当它收到一个请求并发送一个响应时,一个感应器(i ...

  9. Java高并发秒杀系统API之SSM框架集成swagger与AdminLTE

    初衷与整理描述 Java高并发秒杀系统API是来源于网上教程的一个Java项目,也是我接触Java的第一个项目.本来是一枚c#码农,公司计划部分业务转java,于是我利用业务时间自学Java才有了本文 ...

  10. C#面试常见题目

    1.CTS.CLS.CLR分别作何解释 CTS:Common Type System 通用系统类型.Int32.Int16→int.String→string.Boolean→bool CLS:Com ...