PHP 循环的写法对性能的影响

来源:互联网 发布:网络支付安全技术 编辑:程序博客网 时间:2024/06/05 13:43

看过一个博客讨论计算机的体系结构对程序性能的影响,源程序是使用.net写的,我想测试一下PHP是和这种情况一致,下面是程序的源码部分:

<?php $n = 1<<10;$arr = array();for($x = 0; $x < $n; $x++){for($y = 0; $y < $n; $y++){$arr[$x][$y] = $x;}}function sumA(array $arr, $n){$sum = 0;for($y = 0; $y < $n; $y++){for($x = 0; $x < $n; $x++){$sum += $arr[$x][$y];}}return $sum;}function sumB(array $arr, $n){$sum = 0;for($x = 0; $x < $n; $x++){for($y = 0; $y < $n; $y++){$sum += $arr[$x][$y];}}return $sum;}

测试的结果如下:



可以看出,sumB的性能几乎是sumA的一半,而两个函数的功能完全相同,只是循环的方式不同,sumA是先循环靠近内部的,sumB是循环最外部的。两种不同的循环方式带来完全两种不同的程序性能,原博客解释说是因为CPU的高速缓存的原因。

因为,前面构造的二维数据是连续的,因此他们在内存中的存储方式也是连续的,类似这样的顺序存储:

$arr[0][0]、$arr[0][1]、$arr[0][2]、$arr[0][3]、$arr[0][4]……

而sumB的循环方式恰好是按照数据在内存中存储的顺序来读取的,这就可以充分的利用CPU的告诉缓存了,因为CPU在读取某个内存单元的数据时会顺便把其相邻单元的数据一起取出,存储到高速缓存中,也就是CPU的一级缓存、二级缓存、三级缓存等,当程序的下一条指令是需这些相邻的内存单元的数据时,CPU首先查看告诉缓存中有没有这些数据,如果有,就直接取出,不再进行寻址读取内存中的数据,从而节省了时间。而sumA的循环方式是跳跃式的读取内存单元中的数据,这样CPU每次读取数据时都无法命中高速缓存,每次都要从内存中读取,因此效率较低。

下面,我们在增加一个函数sumC,源代码如下:

function sumC(array $arr, $n){$sum = 0;for($x = $n-1; $x >= 0; $x--){for($y = $n-1; $y >= 0; $y--){$sum += $arr[$x][$y];}}return $sum;}

测试的结果如下:




从结果可以看出,sumC的性能又稍微比sumB好一点点,这又是为什么呢?

比较sumB与sumC的代码可以看出,sumC的循环方式是从后面往前面循环的,也就是从最后赋值的的单元开始取值,这种循环方式符合栈的先进后出的特点,最先赋值的单元被push到最下面,最后赋值的单元在最上面,sumC的取值方式每次都是从栈的最上面一个单元pop出值,完全按照栈的操作方式,不会出现跳跃,因此速度也就更快了。

上面的三个函数都是从程序的源代码上分析性能的好坏,其实针对数组的循环操作,最好的方式是使用PHP自带的优化过的foreach循环,这里我们用sumD函数来说明:

function sumD(array $arr, $n){$sum = 0;foreach($arr as $item){foreach($item as $value){$sum += $value;}}return $sum;}

下面的是最终的测试结果,可以看出PHP优化过的foreach循环还是最快的:



原创粉丝点击