本文主要是介绍【19】循环优化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
为了提升循环的效率,编译器会针对循环的编译进行多种方式的优化,比如:循环无关代码外提,循环展开等
1.循环无关代码外提
- 循环无关代码:循环中值不会发生变化的表达式。通过将这些循环无关的代码提出循环外,可避免重复执行这些表达式,实现性能提升。
int foo(int x, int y, int[] a) {int sum = 0;for ( int i = 0; i<a.length; i++) {sum += x * y + a[i];}return sum;
}
循环无关代码:(1)表达式 :x * y (2)循环判断条件:a.length
优化后代码如下:
int foo(int x, int y, int[] a) {int sum = 0;int t0 = x * y;int t1 = a.length;for ( int i = 0; i<t1; i++) {sum += t0 + a[i];}return sum;
2.循环展开
- 循环展开:在循环体中重复多次循环迭代,并减少循环次数的编译优化。
int foo(int x, int y, int[] a) {int sum = 0;for ( int i = 0; i< 64 ; i++) {sum += (i % 2 == 0) ? a[i] : -a[i];}return sum;
}
经过一次展开后,形成如下代码
int foo(int x, int y, int[] a) {int sum = 0;for ( int i = 0; i< 64 ; i += 2) { // 注意这里的步数是2sum += (i % 2 == 0) ? a[i] : -a[i];sum += ((i+1) % 2 == 0) ? a[i+1] : -a[i+1];}return sum;
}
当循环的数目是固定值,且非常小时,即时编译器会将循环全部展开,此时,原本循环中的循环判断语句就不存在了,取而代之的是若干个顺序执行的循环体。
int foo(int[] a) {int sum = 0;for( int i = 0 ; i<4 ;i++ ) {sum += a[i];}return sum;
}
完全展开后
int foo(int[] a) {int sum = 0;sum += a[0];sum += a[1];sum += a[2];sum += a[4];return sum;
}
即使编译器会在循环体的大小和循环展开次数之间做出权衡。
3.循环判断外提
- 将循环中的if语句外提至循环之前,并且在该if语句的两个分支中分别放置一份循环代码
int foo(int[] a) {int sum = 0;for( int i = 0 ; i<a.length ;i++ ) {if(a.length > 4) {sum += a[i];} else {sum += a[i] + 1;}}return sum;
}
经过优化后
int foo(int[] a) {int sum = 0;if(a.length > 4) {for( int i = 0 ; i<a.length ;i++ ) {sum += a[i];} } else {for( int i = 0 ; i<a.length ;i++ ) {sum += a[i] + 1;} }return sum;
}
4.循环剥离
- 循环剥离:将循环的前几个迭代或者后几个迭代剥离出循环的优化方式。背景是循环的前几个迭代或后几个迭代都包含特殊处理。通过将这几个特殊的迭代逻辑剥离后,原本的循环体的规律性更加明显,从而触发进一步的优化。
int foo(int[] a) {int sum = 0;int j = 0;for( int i = 0 ; i<a.length ;i++ ) {sum += a[j];j = i;}return sum;
}
通过剥离第一个迭代,代码如下:
int foo(int[] a) {int sum = 0;if(0 < a.length) {sum += a[0];for( int i = 1; i<a.length ;i++ ) {sum += a[i-1];}}return sum;
}
这篇关于【19】循环优化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!