这三种方法(都用于将一个数组转换为另一个数组)之间的性能差异(如果有)是什么?
foreach
array_map
和λ/关闭功能array_map
带有“静态”函数/方法为了使自己清楚,让我们看一下这些示例,它们都做同样的事情-将数字数组乘以10:
$numbers = range(0, 1000);
佛瑞奇
$result = array();
foreach ($numbers as $number) {
$result[] = $number * 10;
}
return $result;
带有lambda的地图
return array_map(function($number) {
return $number * 10;
}, $numbers);
具有“静态”功能的地图,作为字符串引用传递
function tenTimes($number) {
return $number * 10;
}
return array_map('tenTimes', $numbers);
还有其他方法吗?我将很高兴听到上面案例之间的 所有 实际差异,以及为什么要使用一个案例代替其他案例的任何输入。
FWIW,我只是做了基准测试,因为海报没有做到。在PHP 5.3.10 + XDebug上运行。
更新2015年1月22日与下面的mcfedr的答案进行比较,以获得没有XDebug和更新的PHP版本的其他结果。
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";
}
在十几次尝试中,我得到了与100万个数字相当一致的结果:
假设关闭时地图的缓慢运行是由于每次可能都会评估关闭而造成的,我还进行了如下测试:
function useMapClosure($numbers) {
$closure = function($number) {
return $number * 10;
};
return array_map($closure, $numbers);
}
但是结果是相同的,证实了闭包只被评估了一次。
2014年2月2日更新:操作码转储
这是三个回调的操作码转储。第一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
然后 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
及其调用的闭包:
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
然后useMapNamed()
函数:
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
以及它调用的命名函数_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
null 还有其他办法吗?我将很高兴听到实际所有的差异之间的情况从上面,以及任何输入为什么应该使用一个而不是其他。
我想并行处理一个集合,但我在实现它时遇到了困难,因此我希望得到一些帮助。 foreach方法的原型采用作为参数,但我希望它等待异步lambda。
我正在学习新Java8中的lambdas。有一件事很有趣。如果方法具有与函数接口相同的签名,则可以使用lambdas API将其分配给方法。例如。 这个方法(integer.compare)是静态的,取两个值,一切都很完美。签名与接口方法比较中的签名相同。但这可以用非静态方法来实现,例如 这个方法是非静态的(实例级别),而且它只需要一个值。正如我所理解的,在Java中没有非静态方法,每个方法都是静
问题内容: 有没有办法做这样的事情: 但是,不是调用和,而是直接传递变量? 所需的输出是: 问题答案: 不适用于array_map,因为它不处理键。 array_walk可以: 但是,它确实会更改作为参数给定的数组,因此它不完全是函数式编程(因为您有这样标记的问题)。而且,正如注释中指出的那样,这只会更改数组的值,因此键将不是您在问题中指定的键。 如果需要,您可以编写一个函数来固定自己之上的要点,
我有一个从缓存实例中获取数据的函数,我需要对其进行模拟 IdentityActionsCache类 JUnit与powermock 我无法模仿IdentityActionsCache。getInstance()。getIdentityActionsByName(操作)获取空指针 JAVAcom上的lang.NullPointerException。alnt公司。idm。使用者身份服务。Identi
问题内容: 我正在使用和。我知道,这两个类和是不相容的,但我仍然希望做的相当自然的事情- 我想换了每一个在每个迭代步骤一解析(嵌套内部的)。我尝试这样做: 当我尝试编译此代码时,即使看起来很自然,实际上我也会收到“不兼容的类型”错误。所以,我的问题是迭代的最佳方法是什么? 问题答案: 显然,实现了一个 原始 Iterator。这意味着每个元素都被视为。您可以尝试投射: 这就是在Java 1.4和更