代码之家  ›  专栏  ›  技术社区  ›  John Carter

为什么对引用值调用函数(如strlen、count等)如此慢?

  •  12
  • John Carter  · 技术社区  · 14 年前

    我刚刚在PHP中发现了一些非常奇怪的东西。

    如果我通过引用将一个变量传递给一个函数,然后对它调用一个函数,它就是 慢点。

    如果在内部函数调用上循环,并且变量很大,那么它可能比按值传递变量慢很多数量级。

    例子:

    <?php
    function TestCount(&$aArray)
    {
        $aArray = range(0, 100000);
        $fStartTime = microtime(true);
    
        for ($iIter = 0; $iIter < 1000; $iIter++)
        {
            $iCount = count($aArray);
        }
    
        $fTaken = microtime(true) - $fStartTime;
    
        print "took $fTaken seconds\n";
    }
    
    $aArray = array();
    TestCount($aArray);
    ?>
    

    在我的机器上(在php5.3上)运行这个过程通常需要20秒。

    但是如果我把函数改为按值传递(即 function TestCount($aArray) 而不是 function TestCount(&$aArray) ),然后在大约2毫秒内运行- !

    其他内置函数也是如此,例如 strlen

    发生什么事?

    2 回复  |  直到 14 年前
        1
  •  13
  •   John Carter    14 年前

    我发现了一个2005年的bug报告,它准确地描述了这个问题: http://bugs.php.net/bug.php?id=34540

    这可以通过以下测试代码来证明:

    <?php
    function CalledFunc(&$aData)
    {
        // Do nothing
    }
    
    function TestFunc(&$aArray)
    {
        $aArray = range(0, 100000);
        $fStartTime = microtime(true);
    
        for ($iIter = 0; $iIter < 1000; $iIter++)
        {
            CalledFunc($aArray);
        }
    
        $fTaken = microtime(true) - $fStartTime;
    
        print "took $fTaken seconds\n";
    }
    
    $aArray = array();
    TestFunc($sData);
    ?>
    

    这运行很快,但如果你改变 function CalledFunc(&$aData) function CalledFunc($aData) 你会看到类似的减速 count

    这是相当令人担忧的,因为我已经编写了相当长一段时间的PHP代码,我对这个问题一无所知。

        2
  •  1
  •   Dan McGrath    14 年前

    因此,考虑到您已经给出的答案,您可以通过在迭代工作之前强制复制(如果数据发生更改,则在之后进行复制)部分地避免这个问题。

    <?php
    function TestCountNon($aArray)
    {
        $aArray = range(0, 100000);
        $fStartTime = microtime(true);
        for ($iIter = 0; $iIter < 1000; $iIter++)
        {
            $iCount = count($aArray);
        }
        $fTaken = microtime(true) - $fStartTime;
    
        print "Non took $fTaken seconds\n<br>";
    }
    
    function TestCount(&$aArray)
    {
        $aArray = range(0, 100000);
        $fStartTime = microtime(true);
        for ($iIter = 0; $iIter < 1000; $iIter++)
        {
            $iCount = count($aArray);
        }
        $fTaken = microtime(true) - $fStartTime;
    
        print "took $fTaken seconds\n<br>";
    }
    
    function TestCountA(&$aArray)
    {
        $aArray = range(0, 100000);
        $fStartTime = microtime(true);
        $bArray = $aArray;
        for ($iIter = 0; $iIter < 1000; $iIter++)
        {
            $iCount = count($bArray);
        }
        $aArray = $bArray;
        $fTaken = microtime(true) - $fStartTime;
    
        print "A took $fTaken seconds\n<br>";
    }
    
    $nonArray = array();
    TestCountNon($nonArray);
    
    $aArray = array();
    TestCount($aArray);
    
    $bArray = array();
    TestCountA($bArray);
    ?>
    

    Non took 0.00090217590332031 seconds 
    took 17.676940917969 seconds 
    A took 0.04144287109375 seconds 
    

    不太好,但好得多。