「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」
前言
开发过程中,我们有可能会写段循环语句来执行一段代码,完成一个功能点。运行没问题看到结果后,一切万事大吉,功能完成了就可以了。但对于这段代码背后是如何执行的,很少有人愿意去深究,除非涉及到一些性能问题,不得不改进循环时才会去真正的探究本质。其实对于我们写的循环语句,编译器有可能帮助我们做了一定程度上的优化。这种优化的技术,就叫做Loop Unrolling 。
Loop Unrolling (循环展开)
循环展开,是一种牺牲程序的大小来加快程序执行速度的优化方法。可以由程序员完成,也可由编译器自动优化完成。循环展开最常用来降低循环开销,为具有多个功能单元的处理器提供指令级并行。也有利于指令流水线的调度。
本文主要探讨编译器对于Loop Unrolling优化问题。
有如下代码:
int loop(int i) {
for(;i<10;i++);
return i;
}
复制代码
对于聪明的人类来说,看一下逻辑就可以得到结果,如果参数i小于等于10,则返回10;否则返回i(即一次比较就知道结果)。
但对于编译器来说,在编译代码时会有自己的一套规则。当编辑优化参数设置为-o0时,编译器会按部就班的来执行代码逻辑。
即会按照流程执行for语句,然后再返回结果。如下是汇编结果,
可以看到将值与9比较然后决定是返回循环还是结束循环。
那有没有聪明一点的做法呢?答案是肯定的,在编译器优化选项中设置-o2,编译器会对函数做优化,执行Loop Unrolling,函数会被优化成一条简单的if指令,如下是汇编结果,
可以看到,直接跟10比较来返回结果。
编译器将一个循环转变为不需要循环的过程,这个过程就叫做Loop Unrolling。
有关汇编指令的问题可以去简单的复习一下汇编。
总结
Loop Unrolling 有助于提升App的性能,但也有相应的缺点。它的优缺点如下:
-
优点
-
分支预测失败减少。
-
如果循环結構内语句没有数据相关,增加了并发执行的机会。
-
可以在执行时动态循环展开。这种情况在编译时也不可能掌握。
-
-
缺点
-
代码膨胀
-
代码可读性降低,除非是编译器透明执行循环展开。
-
循环結構内包含递归可能会降低循环展开的效益。
-
近期评论