一.代码移动

将在循环里面多次计算,但是结果不会改变的计算,移到循环外面去。

例子:

优化前:

void lower1(char *s){

int i;

for(i=0;i

if(s[i]>='A'&&s[i]<='Z')

s[i]-=('A'-'a');

}

优化后:

void lower2(char *s){

int i;

int len=strlen(s);

for(int i=0;i

if(s[i]>='A'&&s[i]<='Z')

s[i]-=('A'-'a');

}

优化前的版本,由于每次循环都要调用strlen计算s的长度,实际上的复杂度成了O(n2)了,而优化后的版本只需计算一次s的长度,因此性能上比优化前版本要好。

二.减少函数调用

例子:

优化前:

void sum1(vec_ptr v,data_t *dest){

int i;

int len=vec_length(v);

*dest=0;

for(i=0;i

data_t val;

get_vec_element(v,i,&val);

*dest+=val;

}

}

优化后:

data_t get_vec_start(vec_ptr v){

return v->data;

}

void sum2(vec_ptr v,data_t *dest){

int i;

int len=vec_length(v);

data_t *data=get_vec_start(v);

*dest=0;

for(i=0;i

*dest+=data[i];

}

优化前的版本在每次循环中都要调用一次get_vec_element获得相应的项,而优化后的版本只需在循环外调用一次get_vec_start获得开始的内存地址,循环内直接访问内存,无需调用函数。

三.减少内存访问

例子:

优化前:

void sum2(vec_ptr v,data_t *dest){

int i;

int len=vec_length(v);

data_t *data=get_vec_start(v);

*dest=0;

for(i=0;i

*dest+=data[i];

}

优化后:

void sum3(vec_ptr v,data_t *dest){

int i;

int len=vec_length(v);

data_t *data=get_vec_start(v);

data_t acc=0;

for(i=0;i

acc+=data[i];

*dest=acc;

}

优化前的版本每次迭代都要从dest读出值再加上data[i],再将结果写回dest。这样的读写很浪费,因此每次迭代开始从dest读出的值就是上次迭代写回dest的指。优化后的版本通过加入acc临时变量,它循环中累积计算出的结果,循环结束后再写回。

这里给出两个版本相应的汇编结果就可以很清楚看出区别:

优化前:

优化前的版本每次迭代都要从dest读出值再加上data[i],再将结果写回dest。这样的读写很浪费,因此每次迭代开始从dest读出的值就是上次迭代写回dest的指。优化后的版本通过加入acc临时变量,它循环中累积计算出的结果,循环结束后再写回。

第二行和第四行分别对dest进行了读写。

优化后:

从汇编结果可以看出编译器将acc直接放在了寄存器里,循环中无需对内存进行读写。

四.循环展开

循环展开可以减少循环的次数,对程序的性能带了两方面的提高。一是减少了对循环没有直接贡献的计算,比如循环计数变量的计算,分支跳转指令的执行等。二是提供了进一步利用机器特性进行的优化的机会。

例子:

优化前的代码见前一篇博客里的sum3.

优化后:

void sum4(vec_ptr v,data_t *dest){

int i;

int len=vec_length(v);

int limit=len-3;

data_t *data=get_vec_start(v);

data_t acc=0;

for(i=0;i

acc=acc+data[i]+data[i+1];

acc=acc+data[i+2]+data[i+3];

}

for(;i

acc+=data[i];

*dest=acc;

}

通过循环展开,每次迭代将累加4个元素,减少了循环次数,从而减少了总的执行时间(单独使用这种优化方法,对浮点数累乘几乎没有提高,但是整数累乘得益于编译器的重关联代码变化会有大幅度提高)。

这种优化可以直接利用编译器完成,将优化level设定到较高,编译器会自动进行循环展开。使用gcc,可以显式使用-funroll-loops选项。

五.提高并行性

现代处理器大多采用了流水线、超标量等技术,可以实现指令级并行。我们可以利用这个特性对代码做进一步的优化。

2.1使用多个累积变量

优化代码示例

void sum5(vec_ptr v,data_t *dest){

int i;

int len=vec_length(v);

int limit=len-1;

data_t *data=get_vec_start(v);

data_t acc0=0;

data_t acc1=0;

for(i=0;i

acc0+=data[i];

acc1+=data[i+1];

}

for(;i

acc0+=data[i];

*dest=acc0+acc1;

}

这里同时使用了循环展开和使用多个累加变量,一方面减少了循环次数,另一方面指令级并行的特性使得每次迭代的两次加法可以并行执行。基于这两点可以显著减少程序执行的时间。通过增加展开的次数和累加变量的个数,可以进一步提高程序的性能,直到机器指令执行的吞吐量的极限。

2.2重结合变换

除了使用多个累积变量显式利用机器的指令级并行特性外,还可以对运算重新结合变换,打破顺序相关性来享受指令级并行带来的好处。

在sum4中,acc=acc+data[i]+data[i+1]的结合顺序是acc=(acc+data[i])+data[i+1];

我们将之变成acc=acc+(data[i]+data[i+1]);

代码如下:

void sum6(vec_ptr v,data_t *dest){

int i;

int len=vec_length(v);

int limit=len-3;

data_t *data=get_vec_start(v);

data_t acc=0;

for(i=0;i

acc=acc+(data[i]+data[i+1]);

acc=acc+(data[i+2]+data[i+3]);

}

for(;i

acc+=data[i];

*dest=acc;

}

进一步增加循环展开的次数,可以进一步提高程序性能,最终也可以达到机器指令执行的吞吐量的极限。(在循环展示提到的整数乘法的性能提高就在于编译器隐式采取了这种变换,但是由于浮点数不具备结合性,所以编译器没有采用,但是程序员在保证程序结果正确性的情况下,可以显式使用这一点)。

c语言中循环结构的作用,C语言中对于循环结构优化的一些入门级方法简介相关推荐

  1. c语言什么是循环优化,C语言中对于循环结构优化的一些入门级方法简介

    一.代码移动 将在循环里面多次计算,但是结果不会改变的计算,移到循环外面去. 例子: 优化前: void lower1(char *s){ int i; for(i=0;i if(s[i]>=' ...

  2. c语言中的除号什么作用,c语言中除号用什么表示

    前言继承是OOP设计中的重要概念.在C++语言中,派生类继承基类有三种继承方式:私有继承(private).保护继承(protected)和公有继承(public).一.继承规则继承是C++中的重要特 ...

  3. c语言中 程序各步作用,C语言学习网总结C语言学习五步曲

    很多人对C语言的第一感觉就是太难了,很难理解这种语言,也不知道该如何来理解,书也看了,视频也看了,但就是没什么太大的作用,那么C语言究竟该如何来学? C语言作为一门计算机语言,想要真正的掌握并使用需要 ...

  4. c语言里的%p的作用,c语言中 %p的含义

    格式控制符"%p"中的p是pointer(指针)的缩写.指针的值是语言实现(编译程序)相关的,但几乎所有实现中,指针的值都是一个表示地址空间中某个存储器单元的整数.printf函数 ...

  5. c语言中初始化的主要作用,C语言初始化——栈的初始化

    栈是一种具有后进先出性质的数据组织方式,也就是说后存放的先取出,先存放的后取出.栈底是第一个进栈的数据所处的位置,栈顶是最后一个进栈的数据所处的位置. 1.满栈与空栈 根据SP指针指向的位置,栈可以分 ...

  6. c语言中 小括号的作用,c语言小括号的用法有哪些用处

    C语言的小括号里面表示一条语句,返回值是多条语句中最靠右的语句的返回值,下面学习啦小编就为大家介绍c语言小括号的用法,欢迎大家阅读. c语言小括号的用法:单小括号 () ①命令组.括号中的命令将会新开 ...

  7. c语言中各种函数的作用,C语言常用函数用法大全

    C语言是当中广泛的计算机编程语言,是所有计算机编程语言的祖先,其他计算机编程语言包括当前流行的Java语言,都是用C语言实现的,C语言是编程效率高的计算机语言,既能完成上层应用开发,也能完成底层硬件驱 ...

  8. C语言中动态数组的作用,C语言实现动态数组

    前言 在纯C语言编程中,数组的创建必须是固定的大小,因为C语言本身没有提供动态数组这种数据结构,这是一个让习惯了使用高级语言编程的人转做C开发面临的一个很头疼的问题,本篇文章就将介绍如何使用纯C语言编 ...

  9. c语言for表达式1的作用,C语言for语句用法详解

    C语言for语句用法详解 C语言是一门高级计算机编程语言,设计目标是提供一种能以简易的方式编译.处理低级存储器.产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言.下面小编给大家介绍C语言f ...

最新文章

  1. 学计算机视觉台式机,回顾2020,2020年最受欢迎的7种电脑视觉工具
  2. 13、JsonResponse响应介绍
  3. 虚拟机上SourceInsight访问Linux系统的代码
  4. 高级mysql优化知识_MySQL高级第三篇(索引优化分析)
  5. Spring - Java/J2EE Application Framework 应用框架 第 12 章 Web框架
  6. GDCM:gdcm::ImageChangePlanarConfiguration的测试程序
  7. oracle 移动日志文件,Oracle数据库移动数据文件、日志文件和控制文件
  8. SpringMVC的响应JSON数据和过滤静态资源
  9. win32 c语言编程,win32环境C语言实现最基本的DLL编写及调用实例,测试通过[原]
  10. html sql连接mysql数据库_HTML连接sql数据库
  11. 机器学习与深度学习资料整理
  12. UnitySDK新接入记录
  13. UiPath中文教程PDF
  14. C. New Year Ratings Change
  15. 少年,我看你骨骼精奇,见与你有缘,这套算法赠你
  16. 海信电视power android,海信电视工厂模式中“To Fac”设置“U”、“M”参数不完全对比...
  17. 普元项目更换服务器,服务器图片普元
  18. str_rot13() 函数
  19. Elasticsearch模块——CRUD
  20. iphone怎么投屏到三星电视?这样操作即可实现

热门文章

  1. gcc的简单使用教程
  2. OpenTSDB 开发指南之 查询数据
  3. 37 手游基于 Flink CDC + Hudi 湖仓一体方案实践
  4. 2021杭州·云栖大会来了!门票免费预约!
  5. 为什么说Serverless是云的未来?
  6. 怀里橘猫柴犬,掌上代码江湖——对话阿里云MVP郭旭东
  7. Go语言出现后,Java还是最佳选择吗?
  8. 为什么说流处理即未来?
  9. Data Lake Analytics-数据分析时代迎来新变革
  10. 阿里云上Kubernetes集群联邦 1