性能的foreach,array_map与lambda和array_map与静态函数 [英] Performance of foreach, array_map with lambda and array_map with static function

查看:166
本文介绍了性能的foreach,array_map与lambda和array_map与静态函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这三种方法之间的性能差异(如果有的话),用于将数组转换为另一个数组?


  1. 使用 foreach

  2. 在lambda / closure函数中使用 array_map

  3. 使用 array_map 与'static'函数/方法

  4. 是否有其他方法?

为了让我自己清楚一点,让我们来看看例子,所有这些都是相同的 - 将数组乘以10:
$ b

  $ numbers = range(0,1000); 






Foreach

  $ result = array(); 
foreach($ number为$ number){
$ result [] = $ number * 10;
}
return $ result;






使用lambda映射

  return array_map(function($ number){
return $ number * 10;
},$数字);






作为字符串引用传递

 函数十次($ number){
return $ number * 10;
}
返回array_map('tenTimes',$ numbers);






是否有其他方法?我会很高兴听到上面的情况之间的所有所有区别,以及为什么应该使用其他情况的输入。

解决方案

FWIW,我只是做了基准,因为海报没有这样做。运行在PHP 5.3.10 + XDebug上。



UPDATE 2015-01-22与mcfedr下面的答案比较,没有XDebug和更新的PHP版本的附加结果

  
函数lap($ func){
$ t0 = microtime(1);
$ numbers = range(0,1000000);
$ ret = $ func($ numbers);
$ t1 = microtime(1);
返回数组($ t1 - $ t0,$ ret);


函数useForeach($ numbers){
$ result = array();
foreach($ number为$ number){
$ result [] = $ number * 10;
}
return $ result;

$ b函数useMapClosure($ numbers){
返回array_map(函数($ number){
return $ number * 10;
},$数字);
}

函数_tenTimes($ number){
return $ number * 10;


函数useMapNamed($数字){
返回array_map('_ tenTimes',$ numbers);

$ b $ foreach('foreach','MapClosure','MapNamed')为$ callback){
list($ delay,)= lap(use $回电话);
echo$ callback:$ delay\\\
;
}




  • Foreach:0.7秒
  • 地图封闭:3.4秒
  • $ b
  • 映射函数名称:1.2秒



  • 假设闭包的映射速度平缓是由闭包引起的我也测试过这样:

      
    函数useMapClosure($ numbers){
    $ closure = function($ number){
    return $ number * 10;
    };

    返回array_map($ closure,$ numbers);
    }

    但是结果是一致的,证实了闭包只被计算一次。 / p>

    2014-02-02 UPDATE:opcodes dump



    以下是三个回调的操作码转储。首先 useForeach()

      

    编译的变量:!0 = $ numbers,!1 = $ result,!2 = $ number
    line#* op获取ext返回操作数
    -------------- -------------------------------------------------- -----------------
    10 0> EXT_NOP
    1 RECV 1
    11 2 EXT_STMT
    3 INIT_ARRAY〜0
    4 ASSIGN!1,〜0
    12 5 EXT_STMT
    6> FE_RESET $ 2!0, - > 15
    7>> FE_FETCH $ 3 $ 2, - > 15
    8> OP_DATA
    9 ASSIGN!2,$ 3
    13 10 EXT_STMT
    11 MUL〜6!2,10
    12 ASSIGN_DIM!1
    13 OP_DATA〜6,$ 7
    14 14> JMP - > 7
    15> SWITCH_FREE $ 2
    15 16 EXT_STMT
    17> RETURN!1
    16 18 * EXT_STMT
    19 *> RETURN null

    然后 useMapClosure()

      
    汇编变量:!0 = $数字
    行#* op获取ext返回操作数
    ----------------------------------------- ----------------------------------------
    18 0> EXT_NOP
    1 RECV 1
    19 2 EXT_STMT
    3 EXT_FCALL_BEGIN
    4 DECLARE_LAMBDA_FUNCTION'%00%7Bclosure%7D%2Ftmp%2Flap.php0x7f7fc1424173'
    21 5 SEND_VAL〜0
    6 SEND_VAR!0
    7 DO_FCALL 2 $ 1'array_map'
    8 EXT_FCALL_END
    9> RETURN $ 1
    22 10 * EXT_STMT
    11 *> RETURN null

    和它调用的闭包:

      
    编译的变量:!0 = $ number
    行#* op获取ext返回操作数
    -------------------------------------- -------------------------------------------
    19 0> EXT_NOP
    1 RECV 1
    20 2 EXT_STMT
    3 MUL〜0!0,10
    4> RETURN〜0
    21 5 * EXT_STMT
    6 *> RETURN null

    useMapNamed() / code>函数:

      
    编译的变量:!0 = $ numbers
    行# * op获取ext返回操作数
    ---------------------------------------- -----------------------------------------
    28 0> EXT_NOP
    1 RECV 1
    29 2 EXT_STMT
    3 EXT_FCALL_BEGIN
    4 SEND_VAL'_tenTimes'
    5 SEND_VAR!0
    6 DO_FCALL 2 $ 0'array_map'
    7 EXT_FCALL_END
    8> RETURN $ 0
    30 9 * EXT_STMT
    10 *> RETURN null

    以及它调用的函数 _tenTimes()

      
    编译的变量:!0 = $ number
    行#* op取ext返回操作数
    --------- -------------------------------------------------- ----------------------
    24 0> EXT_NOP
    1 RECV 1
    25 2 EXT_STMT
    3 MUL 〜0!0,1 0
    4> RETURN〜0
    26 5 * EXT_STMT
    6 *> RETURN null


    What's the performance difference (if there is any) between these three approaches, both used to transform an array to another array?

    1. Using foreach
    2. Using array_map with lambda/closure function
    3. Using array_map with 'static' function/method
    4. Is there any other approach?

    To make myself clear, let's have look at the examples, all doing the same - multiplying the array of numbers by 10:

    $numbers = range(0, 1000);
    


    Foreach

    $result = array();
    foreach ($numbers as $number) {
        $result[] = $number * 10;
    }
    return $result;
    


    Map with lambda

    return array_map(function($number) {
        return $number * 10;
    }, $numbers);
    


    Map with 'static' function, passed as string reference

    function tenTimes($number) {
        return $number * 10;
    }
    return array_map('tenTimes', $numbers);
    


    Is there any other approach? I will be happy to hear actually all differences between the cases from above, and any inputs why one should be used instead of others.

    解决方案

    FWIW, I just did the benchmark since poster didn't do it. Running on PHP 5.3.10 + XDebug.

    UPDATE 2015-01-22 compare with mcfedr's answer below for additional results without XDebug and a more recent PHP version.

    
    function lap($func) {
      $t0 = microtime(1);
      $numbers = range(0, 1000000);
      $ret = $func($numbers);
      $t1 = microtime(1);
      return array($t1 - $t0, $ret);
    }
    
    function useForeach($numbers)  {
      $result = array();
      foreach ($numbers as $number) {
          $result[] = $number * 10;
      }
      return $result;
    }
    
    function useMapClosure($numbers) {
      return array_map(function($number) {
          return $number * 10;
      }, $numbers);
    }
    
    function _tenTimes($number) {
        return $number * 10;
    }
    
    function useMapNamed($numbers) {
      return array_map('_tenTimes', $numbers);
    }
    
    foreach (array('Foreach', 'MapClosure', 'MapNamed') as $callback) {
      list($delay,) = lap("use$callback");
      echo "$callback: $delay\n";
    }
    
    

    I get pretty consistent results with 1M numbers across a dozen attempts:

    • Foreach: 0.7 sec
    • Map on closure: 3.4 sec
    • Map on function name: 1.2 sec.

    Supposing the lackluster speed of the map on closure was caused by the closure possibly being evaluated each time, I also tested like this:

    
    function useMapClosure($numbers) {
      $closure = function($number) {
        return $number * 10;
      };
    
      return array_map($closure, $numbers);
    }
    

    But the results are identical, confirming that the closure is only evaluated once.

    2014-02-02 UPDATE: opcodes dump

    Here are the opcode dumps for the three callbacks. First useForeach():

    
    
    compiled vars:  !0 = $numbers, !1 = $result, !2 = $number
    line     # *  op                           fetch          ext  return  operands
    ---------------------------------------------------------------------------------
      10     0  >   EXT_NOP                                                  
             1      RECV                                                     1
      11     2      EXT_STMT                                                 
             3      INIT_ARRAY                                       ~0      
             4      ASSIGN                                                   !1, ~0
      12     5      EXT_STMT                                                 
             6    > FE_RESET                                         $2      !0, ->15
             7  > > FE_FETCH                                         $3      $2, ->15
             8  >   OP_DATA                                                  
             9      ASSIGN                                                   !2, $3
      13    10      EXT_STMT                                                 
            11      MUL                                              ~6      !2, 10
            12      ASSIGN_DIM                                               !1
            13      OP_DATA                                                  ~6, $7
      14    14    > JMP                                                      ->7
            15  >   SWITCH_FREE                                              $2
      15    16      EXT_STMT                                                 
            17    > RETURN                                                   !1
      16    18*     EXT_STMT                                                 
            19*   > RETURN                                                   null
    

    Then the useMapClosure()

    
    compiled vars:  !0 = $numbers
    line     # *  op                           fetch          ext  return  operands
    ---------------------------------------------------------------------------------
      18     0  >   EXT_NOP                                                  
             1      RECV                                                     1
      19     2      EXT_STMT                                                 
             3      EXT_FCALL_BEGIN                                          
             4      DECLARE_LAMBDA_FUNCTION                                  '%00%7Bclosure%7D%2Ftmp%2Flap.php0x7f7fc1424173'
      21     5      SEND_VAL                                                 ~0
             6      SEND_VAR                                                 !0
             7      DO_FCALL                                      2  $1      'array_map'
             8      EXT_FCALL_END                                            
             9    > RETURN                                                   $1
      22    10*     EXT_STMT                                                 
            11*   > RETURN                                                   null
    

    and the closure it calls:

    
    compiled vars:  !0 = $number
    line     # *  op                           fetch          ext  return  operands
    ---------------------------------------------------------------------------------
      19     0  >   EXT_NOP                                                  
             1      RECV                                                     1
      20     2      EXT_STMT                                                 
             3      MUL                                              ~0      !0, 10
             4    > RETURN                                                   ~0
      21     5*     EXT_STMT                                                 
             6*   > RETURN                                                   null
    

    then the useMapNamed() function:

    
    compiled vars:  !0 = $numbers
    line     # *  op                           fetch          ext  return  operands
    ---------------------------------------------------------------------------------
      28     0  >   EXT_NOP                                                  
             1      RECV                                                     1
      29     2      EXT_STMT                                                 
             3      EXT_FCALL_BEGIN                                          
             4      SEND_VAL                                                 '_tenTimes'
             5      SEND_VAR                                                 !0
             6      DO_FCALL                                      2  $0      'array_map'
             7      EXT_FCALL_END                                            
             8    > RETURN                                                   $0
      30     9*     EXT_STMT                                                 
            10*   > RETURN                                                   null
    

    and the named function it calls, _tenTimes():

    
    compiled vars:  !0 = $number
    line     # *  op                           fetch          ext  return  operands
    ---------------------------------------------------------------------------------
      24     0  >   EXT_NOP                                                  
             1      RECV                                                     1
      25     2      EXT_STMT                                                 
             3      MUL                                              ~0      !0, 10
             4    > RETURN                                                   ~0
      26     5*     EXT_STMT                                                 
             6*   > RETURN                                                   null
    
    

    这篇关于性能的foreach,array_map与lambda和array_map与静态函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆