一个记录自己的地方,一个用于分享的地方



  1. 首页
  2. 文章详情
  3. php中for循环的极致性能论证

php中for循环的极致性能论证

简介:

$i++与++$i两种写法对for循环影响到底多么大,以及count的位置对于提高for循环效率的写法影响又多么大?for($i=0;$i<count($arr);$i++)的写法差不多可以抛弃了;

测试环境:

PS F:\Study-work\php\ceshizhuanyong> php -v
PHP 7.2.4 (cli) (built: Mar 28 2018 04:27:01) ( ZTS MSVC15 (Visual C++ 2017) x64 )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies

说法一:【for($i = 0; $i < 10000; $i++)】中$i++如果改成++$i速度将会提升

测试:

代码如下:

<?php
    //php官方手册封装的一个用于获取当前含微秒时间的函数,所以我怎么可能客气呢
    function microtime_float()                                
    {                                                        
        list($usec, $sec) = explode(" ", microtime());
        return ((float)$usec + (float)$sec);
    }

    $arr = [];                                                //预定义数组,方便统计平均数
    for($j = 1; $j <=10; $j++){                               //避免出现误差,直接连续测十次        
        $start_time = microtime_float();                      //获取初始时间
        for($i = 0; $i < 10000; $i++){                        //测试一万次循环下$i++和++$i的用时
            continue;                                         //直接跳过,避免影响对结果的判断
        }
        $end_time = microtime_float();                        //获取结束时间
        $arr[$j] = ($end_time-$start_time);                   //保存至数组,后面计算
        echo "第{$j}次用时:".($end_time-$start_time)."秒\n"; //输出每一次的结果
    }
    echo "平均用时:".(array_sum($arr)/10)."秒";              //计算平均值

$i++结果如下:

Snipaste_2018-11-28_14-58-03.png

++$i结果如下:

++$i.png

所以,结果是:

一万次循环下$i++比++$i快了0.00009秒

四舍五入那可是一个亿呢0.0001秒呢!时间如金呀!

u=4127184032,546818021&fm=27&gp=0.jpg

不过这是量级不够的情况下,如果我们将次数再翻一万倍,提高到1亿次,前后写++影响可以达到一秒左右。

原理:

$i++是先引用,再对$i进行自增,而++$i是先对$i进行自增,然后再进行引用。

如果是一个完整的函数的话,那么$i++需要做的就是以下三步

$j = $i;
$i += 1;
return $j

++$i需要做的是

$i += 1
return $i

所以,$i++在执行的时候,将会在内存中多开辟一个临时变量的位置,那么,效率肯定要低。

所以结论是:

一般数据量下,两种写法的差距影响并没有那么大,所以,怎么写都行,如果在亿级数据量时,++$i的写法可以影响该循环提高程序运行时间一秒左右的时间。

说法二:遍历数组时【for($i = 0; $i < count($arr); $i++)】速度很慢

测试: 

普通写法代码如下:

<?php
    //php官方手册封装的一个用于获取当前含微秒时间的函数,所以我怎么可能客气呢
    function microtime_float()                                
    {                                                         
        list($usec, $sec) = explode(" ", microtime());
        return ((float)$usec + (float)$sec);
    }

    $list_arr = [];                                           //生成一个用于遍历的数组
    for($i=0;$i<10000;$i++){                                  //数组长度为一万的
        $list_arr[$i] = $i;
    }
    
    $arr = [];                                                //预定义数组,方便统计平均数
    for($j = 1; $j <=10; $j++){                               //避免出现误差,直接连续测十次  
      
        $start_time = microtime_float();                      //获取初始时间

        for($i = 0; $i < count($list_arr); ++$i){             //普通的写法,后面果断使用++$i提高运行速度
            continue;                                         //直接跳过,避免影响对结果的判断
        }
        $end_time = microtime_float();                        //获取结束时间

        $arr[$j] = ($end_time-$start_time);                   //保存至数组,后面计算
        echo "第{$j}次用时:".($end_time-$start_time)."秒\n"; //输出每一次的结果
    }
    echo "平均用时:".(array_sum($arr)/10)."秒";              //计算输出平均值

结果如下:

普通写法.png

将for换个写法,代码如下:

<?php
    function microtime_float()                                
    {                                                         
        list($usec, $sec) = explode(" ", microtime());
        return ((float)$usec + (float)$sec);
    }

    $list_arr = [];                                           
    for($i=0;$i<10000;$i++){                                  
        $list_arr[$i] = $i;
    }
    
    $arr = [];                                                
    for($j = 1; $j <=10; $j++){                               
      
        $start_time = microtime_float();                      
        //将count位置换到第一段代码定义,并在后面仅选择变量
        for($i = 0, $count = count($list_arr); $i < $count; ++$i){ 
            continue;                                         
        }
        $end_time = microtime_float();                        

        $arr[$j] = ($end_time-$start_time);                   
        echo "第{$j}次用时:".($end_time-$start_time)."秒\n"; 
    }
    echo "平均用时:".(array_sum($arr)/10)."秒";

结果如下:

for循环第二种写法.png

所以结果是一万次循环平均快了0.00008秒

结果与上面$i++的写法的影响近乎一样

同理,亿级数据一样影响接近一秒的时间差值。

原理:

这个是因为for循环执行顺序的问题,for循环执行顺序如下:

for(第一段;第二段;第四段){

第三段

}

第一段仅在循环开始之前执行,整个循环仅执行一次;

然后每次循环过程依次执行判断第二段布尔值,执行第三段第四段代码;

所以因为第二段代码每次循环都要执行,$i<count($arr)的写法将会将count这个函数执行N次;

如果将函数放到第一段里进行定义或者循环外部定义,那么速度肯定会更快。

所以结论是:

和上面差不多。一般情况下,影响不大,亿级数据将会影响明显;

所以以后我的for循环遍历就这么写了:

for($i = 0, $c = count($list_arr); $i < $c; ++$i){
    continue;
}

最后试试,php7.2.4版本下两种方法都用和不用的万次循环差别:

for($i=0;$i<count($arr);$i++){}的结果如下:

旧版写法.png

for($i=0,$count = count($arr);$i<$count;++$i){}的结果如下:

新版写法.png

时间差值约为:0.00013秒

其实是接近一倍的时间存在

php5.6.34版本下两种方法都用和不用的万次循环差别:

for($i=0;$i<count($arr);$i++){}的结果如下: 

5.6旧写法.png


for($i=0,$count = count($arr);$i<$count;++$i){}的结果如下:

5.6版本.png

时间差值约为:0.0008秒

差值已经非常明显,亿级数据可以直接差别到8秒钟

封面结尾:

f10.jpg



评论