什么是最快的?循环内部或外部的条件?

Posted

技术标签:

【中文标题】什么是最快的?循环内部或外部的条件?【英文标题】:What is quickest? Conditions inside a loop or outside? 【发布时间】:2012-09-10 21:59:47 【问题描述】:

什么是最快的? 基于循环外的变量在循环内部或外部执行条件,或者它甚至重要(编译器是否为您执行),或者您是否应该使用完全不同的解决方法?

示例 #1 与循环内的条件(单个 foreach):

$test = 2;  
foreach ($list as $listItem) 
    if ($test == 1) 
        $listItem .= " - one";
     else if ($test == 2) 
        $listItem .= " - two";
     else if ($test == 3) 
        $listItem .= " - three";
    

示例 #2 与循环外的条件(对于多个 foreach 非常难看):

$test = 2;  
if ($test == 1) 
    foreach ($list as $listItem) 
        $listItem .= " - one";
    
 else if ($test == 2) 
    foreach ($list as $listItem) 
        $listItem .= " - two";
    
 else if ($test == 3) 
    foreach ($list as $listItem) 
        $listItem .= " - three";
    

【问题讨论】:

【参考方案1】:

您可能已经猜到了,示例 #2 更快,编译器不会为您执行此操作。

概述


性能测试

示例 #1,循环内的条件:

Time taken: 0.2501 seconds
Time taken: 0.2336 seconds
Time taken: 0.2335 seconds
Time taken: 0.2319 seconds
Time taken: 0.2337 seconds 
Average:    0.2364 seconds

还有代码:

<?php
    $list = array();
    for ($i = 0; $i < 1000000; $i++) 
        $list[] = md5(rand(0, 100000) * $i);
    
    $a = microtime(true);
    $test = 2;
    foreach ($list as $listItem) 
        if ($test == 1) 
            $listItem .= " - one";
         else if ($test == 2) 
            $listItem .= " - two";
         else if ($test == 3) 
            $listItem .= " - three";
        
    
    echo "Time taken: " . number_format(microtime(true) - $a, 4) . " seconds";
?>

示例 #2,循环外的条件:

Time taken: 0.1424 seconds
Time taken: 0.1426 seconds
Time taken: 0.1364 seconds
Time taken: 0.1348 seconds
Time taken: 0.1347 seconds
Average:    0.1382 seconds

还有代码:

<?php
    $list = array();
    for ($i = 0; $i < 1000000; $i++) 
        $list[] = md5(rand(0, 100000) * $i);
    
    $a = microtime(true);
    $test = 2;
    if ($test == 1) 
        foreach ($list as $listItem) 
            $listItem .= " - one";
        
     else if ($test == 2) 
        foreach ($list as $listItem) 
            $listItem .= " - two";
        
     else if ($test == 3) 
        foreach ($list as $listItem) 
            $listItem .= " - three";
        
    
    echo "Time taken: " . number_format(microtime(true) - $a, 4) . " seconds";
?>

好吧,这对于循环之外的条件来说是一个非常明显的胜利,但是如果我们尝试与布尔值而不是 int 进行比较呢?

示例 #3,在循环内设置条件,但使用布尔值代替:

Time taken: 0.1845 seconds
Time taken: 0.1821 seconds
Time taken: 0.1745 seconds
Time taken: 0.1777 seconds
Time taken: 0.1767 seconds
Average:    0.1791 seconds

还有代码:

<?php
    $list = array();
    for ($i = 0; $i < 1000000; $i++) 
        $list[] = md5(rand(0, 100000) * $i);
    
    $a = microtime(true);
    $test = 2;
    $result1 = ($test == 1);
    $result2 = ($test == 2);
    $result3 = ($test == 3);
    foreach ($list as $listItem) 
        if ($result1) 
            $listItem .= " - one";
         else if ($result2) 
            $listItem .= " - two";
         else if ($result3) 
            $listItem .= " - three";
        
    
    echo "Time taken: " . number_format(microtime(true) - $a, 4) . " seconds";
?>

很有趣。如果我们使用 array_walk 这样的内置函数会怎样?

示例 #4,array_walk

Time taken: 0.4950 seconds
Time taken: 0.4946 seconds
Time taken: 0.4947 seconds
Time taken: 0.4937 seconds
Time taken: 0.4918 seconds
Average:    0.4940 seconds

还有代码:

<?php
    function append_string($value, $suffix) 
        return $value . $suffix;
    

    $list = array();
    for ($i = 0; $i < 1000000; $i++) 
        $list[] = md5(rand(0, 100000) * $i);
    
    $a = microtime(true);
    $test = 2;
    if ($test == 1) 
        array_walk($list, "append_string", " - one");
     else if ($test == 2) 
        array_walk($list, "append_string", " - two");
     else if ($test == 3) 
        array_walk($list, "append_string", " - three");
    
    echo "Time taken: " . number_format(microtime(true) - $a, 4) . " seconds";
?>

什么?! 您可能认为内置函数会将其抽象为 C 或 C++ 函数,这可能很好,但问题是函数调用使此方法非常很慢。


优点/缺点

示例 #1 专业人士

您不必多次声明循环(如果您有多个条件,这可能会很烦人)

示例 #1 缺点

它是前 3 个测试中最慢的一个(比 example #2 慢 71%,比 example #3 慢 32%)

示例 #2 专业人士

其中最快的一个

示例 #2 缺点

它需要您多次声明循环(与您拥有的条件数量一样多)

示例 #3 专业人士

您不必多次声明循环,就像在 示例 #1 中一样 比#example 1

示例#3 缺点

还是比#example 2慢(大约30%) 看起来比较凌乱

示例 #4 专业人士

语法看起来很简单

示例 #4 缺点

它是最慢的一个(比第二慢的大约慢 100%(example #1))。可能是因为它必须调用一个函数 1,000,000 次。 您不在全局范围内,必须global 全局范围内的所有变量。

结论

PHP 编译器不会为你做这件事,如果你想要性能,你应该去 example #2然而这个测试是用一个数组进行的有一百万个条目。您的数组可能不会有那么多条目,因此您可能会选择 example #1example #3哦,不要使用 示例 #4

【讨论】:

【参考方案2】:

如果条件测试的结果在循环期间不会改变,那么将测试移出循环总是会更快。 (做一件事显然比多次做同样的事情要快)。

但是,当将条件移出循环时,您不想为每种情况一遍又一遍地重复相同的代码。这就是array_map 的用武之地。例如:

function append_str($value, $suffix) 
    return $value . $suffix;


if ($test == 1)
    array_map("append_str", $list, " - one");
else if ($test == 2)
    array_map("append_str", $list, " - two");
else if ($test == 3)
    array_map("append_str", $list, " - three");

这允许您检查条件一次重用您的代码来处理每种情况。如示例所示,您可以对每种情况的函数调用进行参数化,并且可以根据需要使函数 (append_str) 变得复杂。

注意:值得对此进行基准测试以进行比较,因为array_map 的循环可能是在 C/C++ 中执行的,这应该比原生 PHP 循环更快(类似于 Perl 的 map 函数)。

【讨论】:

虽然这不是对确切示例的错误答案,但问题更多的是关于性能,$listItem .= " - number" 是一个纯粹的示例。可能是 $number += 12$number += 23$number += 34 或者更高级的东西。 我应该补充一点,我正要将此添加到基准测试中,但是; Warning: array_map() [function.array-map]: Argument #3 should be an array in benchmark.php on line 15(第 15 行是 array_map("append_str", $list, " - two");)。根据 PHP 的语法是 array array_map ( callable $callback , array $arr1 [, array $... ] ),因此没有“参数”本身,但是,它应该可以工作,但前提是您添加一个名为 " - two" 的包含 1,000,000 个条目的数组。也就是说,array_walk 可能是您正在寻找的,与之前最慢的 0.25 秒相比,它需要 0.49 秒。 这是一个相当令人惊讶的结果......甚至可能是语言设计失败。不过很高兴您对其进行了测试。

以上是关于什么是最快的?循环内部或外部的条件?的主要内容,如果未能解决你的问题,请参考以下文章

php中在循环外部如何强制结束循环?

循环语句的嵌套及练习题

php中在循环外部如何强制结束循环?

如果函数内部的条件失败,则跳过 bash while 循环

完成这些任务的最快方法是啥?

不使用数组或循环找到五个给定数字中第三大的最快方法?