性能的foreach,array_map与lambda和array_map与静态函数 [英] Performance of foreach, array_map with lambda and array_map with static function
问题描述
这三种方法之间的性能差异(如果有的话),用于将数组转换为另一个数组?
- 使用
foreach
- 在lambda / closure函数中使用
array_map
- 使用
array_map
与'static'函数/方法 - 是否有其他方法?
为了让我自己清楚一点,让我们来看看例子,所有这些都是相同的 - 将数组乘以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?
- Using
foreach
- Using
array_map
with lambda/closure function - Using
array_map
with 'static' function/method - 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屋!