news 2026/5/5 8:52:51

跟我学C++中级篇——循环展开的分

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
跟我学C++中级篇——循环展开的分

一、循环展开

什么是循环展开?为什么要循环展开?可能对不少的程序员来说,循环展开,loop unrolling。它是一种编译器优化的技术,它的本质是通过减少条件分支和运行时的pipeline停顿来提升性能,并有可能提高缓存的命中率。
C++中的循环展开,相对于其它语言来说可能操作更具有灵活性。这种优化一般应用于循环的迭代次数相对较少,而且每次迭代计算量较大的情况。网上有些资料把其称为短循环。

二、循环展开的方式和分析

一般来说,循环展开的方式主要有两个方向即手动展开和自动展开。手动展开依赖开发者自己把循环按实际的场景进行展开而自动展开依赖于编译器及其它辅助的技术。

  1. 手动循环展开
    手动循环展开非常好理解,就是将循环体的操作的代码人工操作多次,这样就会减少循环执行的次数。当然这需要开发者自己仔细衡量并平衡相关的代价。如下面的例子:
for(inti=0;i<16;i++){arr[i]=i*2;}// 展开5次for(inti=0;i<4;i+=4){arr[i]=i*2;arr[i+1]=(i+1)*2;arr[i+2]=(i+2)*2;arr[i+3]=(i+3)*2;arr[i+4]=(i+4)*2;}

说简单些就是ctrl+c,ctrl+v大法。强调一下,之所以称之为短循环,一般是循环次数不太大(16次以下)时才有优势。其实就是分支预测耗时大于循环消耗时才有优势。
也可以使用switch中的fallthrough方法:

voidworking(intn,int*a,int*b){if(n<0||n>16){return;}switch(n){casen:a[n]=b[n]*2;...case2:a[1]=b[1]*2;case1:a[0]=b[0]*2;case0:break;}}
  1. 自动循环展开
    自动循环展开一般有两种情况:
    1) 使用编译优化选项
    如在编译时增加-O2 或-O3(注意O大写,小写表示输出选项)
    2)使用预编译展开选项
    即在代码中使用"#pragma GCC unroll N"或“#pragma unroll”,但需要注意,这个N是一个具体数值。另外,循环中判断退出的大小值,建议是一个常量,否则可能无法进行完全展开而只进行部分展开。
#pragmaGCC unroll4for(inti=0;i<4*n;i++){arr[i]=i*2;}

部分展开的意思是上面的4*n如果换成任意数,可能不是5的倍数,那么编译器就会展开5的倍数部分,而余下则不展开直接循环。其实就是能快一点是一点。这叫做循环剥离+部分展开(loop peeling+Partial Unrolling)。

循环展开之所以能提升性能,主要就在于通过展开,减少了循环控制中的条件判断和指令跳转(减少流水线的扰动),提高了CPU指令执行的并行机会。减少了变量迭代更新的次数(包括加减等操作)。而循环内大的数据计算,又可能导致内存缓存的命中率有可能提升(只是有可能,毕竟相邻数据多了),这样就有了提高性能的前提和基础。
循环展开需要实际情况进行恰当的应用,因为循环展开的结果未必能完全保证提升性能或者说达不到优化的目的。主要原因在于面对过长的循环且内部复杂时,过度的展开可能引起严重的代码膨胀(有点类似于内联和模板啊)。而如果代码的大小超过了缓存的容量,就需要不断的去内存取指。这样,反而可能导致性能的下降。其次,过多的展开,导致寄存器的大占用,会导致CPU的寄存器耗尽,不断的将相关的数据转移到内存,降低性能。当然,还有些循环是不适合循环展开的,比如循环过少或循环内存在在很复杂的分支条件等,此时的循环展开其实是没有什么优化的余地的。
综合上述,在进行循环优化时,一定要仔细考虑,不要为了展开而展开。一定要从最终的性能测试结果出发,有根据的进行循环展开的优化。

三、循环展开的缺点

循环展开时,编译器无法对过长的循环进行完全的展开,但可以进行部分展开或开发者自行利用手动再加一些编译期优化代码技术进行运行时的动态处理。这就增加了对开发者的要求。其主要的缺点有:

  1. 最直观就是代码变得不易理解和维护
  2. 过多的展开有可能导致性能降低的情况,如内存数据的读写和数据的溢出到内存(包括代码膨胀导致的溢出)
  3. 循环展开的优化的兼容性低。不同的硬件平台、编译平台和系统可能导致不同的结果

在现代的CPU中,使用SIMD反而可能会有更好的效果,所以在编译时提供能够自动向量化的标记(-O3 -march=native)反而可能会有更好的效果。

四、循环展开的高级用法

循环展开除了前面提到的方法,还可以使用模板技术和c++17以后的新的方式来进行:

  1. 模板或元编程方式
    看代码:
template<intN>structuLoop{template<typename F>staticvoidinvoke(F func){uLoop<N-1>::invoke(func);func(N-1);}};// 终止递归的特化条件template<>structuLoop<0>{template<typename F>staticvoidinvoke(F func){}};intarr[10];uLoop<16>::invoke(arr);
  1. 使用常量表达式或索引展开
    使用新标准的代码:
template<intN>voidunrollTest(intn,float*a,constfloat*b){if(N<=n){a[N-1]=b[N-1]*2;}ifconstexpr(N>1){unrollTest<N-1>(n,a,b);}}voidworking(intn,float*a,constfloat*b){if(n<=8){unrollTest<8>(n,a,b);}}//std::make_index_sequence#include<utility>#include<array>template<typename T,std::size_t...id>voidunrollInvoke(T*arr,std::index_sequence<id...>){((arr[id]=id*2),...);// 折叠表达式}template<std::size_tN>voidunrollDemo(std::array<int,N>&arr){unrollInvoke(arr.data(),std::make_index_sequence<N>{});}std::array<int,16>arr;unrollDemo(arr);

另外顺道提到一下,实际开发中也可以利用宏展开的方式进行循环展开的优化,但宏的应用不是特别推荐的方法,大家有兴趣可以自行查找相关的资料即可。

五、总结

循环优化在现在的技术看来,应该不是一个好的优化方法。当然,在某些情况下,还是有可能有着不错的优化结果的。这就看开发者对选择的循环展开大小、边界控制等的整体把握了。不过,推荐还是使用编译器进行处理并尽量采用SIMD等现代的并行技术。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/30 23:11:54

5分钟掌握GitHub入门教程优化:从零基础到高效协作

5分钟掌握GitHub入门教程优化&#xff1a;从零基础到高效协作 【免费下载链接】introduction-to-github Get started using GitHub in less than an hour. 项目地址: https://gitcode.com/GitHub_Trending/in/introduction-to-github 想要快速掌握GitHub的使用技巧&…

作者头像 李华
网站建设 2026/4/30 23:34:02

快速上手:Color Thief智能配色方案实战指南

快速上手&#xff1a;Color Thief智能配色方案实战指南 【免费下载链接】color-thief Grab the color palette from an image using just Javascript. Works in the browser and in Node. 项目地址: https://gitcode.com/gh_mirrors/co/color-thief 面对品牌视觉统一和网…

作者头像 李华
网站建设 2026/4/30 23:35:49

A16z 谈 AI 留存的「水晶鞋效应」:第一个月,决定了一切 都是一次认真“试鞋”的机会:这一次,能不能真的解决我手里的问题?

A16z 谈 AI 留存的「水晶鞋效应」&#xff1a;第一个月&#xff0c;决定了一切 原创 Cubo Group 矩阵魔方AI出海 2025年12月12日 19:45 陕西 在传统 SaaS 时代&#xff0c;有一条几乎没人怀疑的共识&#xff1a;产品早期留存差&#xff0c;是正常现象。 MVP 功能不全&#…

作者头像 李华
网站建设 2026/5/2 17:34:40

5、深入了解 Ubuntu 网络配置与 X Window 系统

深入了解 Ubuntu 网络配置与 X Window 系统 1. Ubuntu 无线网络配置 在过去,为 Linux 系统配置无线网络是一件非常繁琐的事情,需要执行许多复杂的步骤才能连接到无线网络。不过,现在情况有了很大的改善。Ubuntu 系统中包含了一个名为 Network Manager 的实用工具,它让连接…

作者头像 李华
网站建设 2026/4/30 23:11:06

分享几则中年夫妻关系的有益建议

著名演员何晴去世了&#xff0c;很震惊&#xff0c;她是我最喜欢的女演员&#xff0c;曾经出演过四大名著。分享几则中年夫妻关系的有益建议&#xff1a; 1、可以容忍对方的生活习惯。包括拉S放P、不叠被、不洗衣&#xff0c;但要管好自己&#xff0c;还是尽量别过份坦荡。 2、…

作者头像 李华
网站建设 2026/5/1 0:12:04

(108页PPT)园区大数据治理解决方案(附下载方式)

篇幅所限&#xff0c;本文只提供部分资料内容&#xff0c;完整资料请看下面链接 &#xff08;108页PPT&#xff09;园区大数据治理解决方案.pptx_智慧园区总体规划PPT资源-CSDN下载 资料解读&#xff1a;《园区大数据治理解决方案》 详细资料请看本解读文章的最后内容。 在数…

作者头像 李华