Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP闭包提供了奇怪的性能行为_Php_Performance_Closures_Anonymous Function - Fatal编程技术网

PHP闭包提供了奇怪的性能行为

PHP闭包提供了奇怪的性能行为,php,performance,closures,anonymous-function,Php,Performance,Closures,Anonymous Function,今天早些时候,我正在开发一个PHP5.3+应用程序,这意味着我可以自由使用PHP闭包。我想太好了!然后我遇到了一段代码,其中使用函数式PHP代码会使事情变得更简单,但是,虽然我有一个合乎逻辑的答案,但这让我想知道直接调用array\u map()中的闭包和将其作为变量传递之间的性能影响。即以下两项: $test_array = array('test', 'test', 'test', 'test', 'test' ); array_map( function ( $item ) { retur

今天早些时候,我正在开发一个PHP5.3+应用程序,这意味着我可以自由使用PHP闭包。我想太好了!然后我遇到了一段代码,其中使用函数式PHP代码会使事情变得更简单,但是,虽然我有一个合乎逻辑的答案,但这让我想知道直接调用
array\u map()
中的闭包和将其作为变量传递之间的性能影响。即以下两项:

$test_array = array('test', 'test', 'test', 'test', 'test' );
array_map( function ( $item ) { return $item; }, $test_array );

正如我所想,后者确实更快,但差别并没有那么大。事实上,重复相同测试10000次并取平均值的差异为0.05秒。甚至可能是侥幸

这让我更加好奇。那么
创建函数()和闭包呢?同样,经验告诉我,
create\u function()
在创建函数、对其求值,然后将其存储的过程中,遇到类似于
array\u map()
的情况时应该会慢一些。 而且,正如我所想,
create\u function()
确实要慢一些。这一切都是通过
array\u map()
实现的

然后,我不知道为什么要这样做,但是我做了,我检查了
create\u function()
和闭包之间的区别,同时保存它并只调用一次。无需处理,无需任何操作,只需传递一个字符串,然后返回该字符串

测试结果如下:

$fn = function($item) { return $item; };
$fn('test');

我对这两个测试各进行了10000次,查看结果,得出平均值。我对结果感到非常惊讶

事实证明,这次关闭速度慢了大约4倍。我想这不可能。我的意思是,通过
array\u map()
运行闭包要快得多,通过
array\u map()
通过变量运行相同的函数要快得多,这与此测试基本相同

结果是

array
  0 => 
    array
      'test' => string 'Closure test' (length=12)
      'iterations' => int 10000
      'time' => float 5.1327705383301E-6
  1 => 
    array
      'test' => string 'Anonymous test' (length=14)
      'iterations' => int 10000
      'time' => float 1.6745710372925E-5
出于好奇,我检查了CPU使用情况和其他系统资源,确保没有不必要的东西在运行,现在一切正常,所以我再次运行了测试,但我得到了类似的结果

因此,我只尝试了一次相同的测试,并运行了多次(当然每次都计时)。结果表明,闭包的速度确实慢了4倍,只是偶尔会比
create\u function()
快两三倍,我想这只是侥幸,但这似乎足以将我进行1000次测试的时间缩短一半

下面是我用来做这些测试的代码。谁能告诉我这到底是怎么回事?这是我的代码还是PHP出了问题

<?php

/**
 * Simple class to benchmark code
 */
class Benchmark
{
    /**
     * This will contain the results of the benchmarks.
     * There is no distinction between averages and just one runs
     */
    private $_results = array();

    /**
     * Disable PHP's time limit and PHP's memory limit!
     * These benchmarks may take some resources
     */
    public function __construct() {
        set_time_limit( 0 );
        ini_set('memory_limit', '1024M');
    }

    /**
     * The function that times a piece of code
     * @param string $name Name of the test. Must not have been used before
     * @param callable|closure $callback A callback for the code to run.
     * @param boolean|integer $multiple optional How many times should the code be run,
     * if false, only once, else run it $multiple times, and store the average as the benchmark
     * @return Benchmark $this
     */
    public function time( $name, $callback, $multiple = false )
    {
        if($multiple === false) {
            // run and time the test
            $start = microtime( true );
            $callback();
            $end = microtime( true );

            // add the results to the results array
            $this->_results[] = array(
                'test' => $name,
                'iterations' => 1,
                'time' => $end - $start
            );
        } else {
            // set a default if $multiple is set to true
            if($multiple === true) {
                $multiple = 10000;
            }

            // run the test $multiple times and time it every time
            $total_time = 0;
            for($i=1;$i<=$multiple;$i++) {
                $start = microtime( true );
                $callback();
                $end = microtime( true );
                $total_time += $end - $start;
            }
            // calculate the average and add it to the results
            $this->_results[] = array(
                'test' => $name,
                'iterations' => $multiple,
                'time' => $total_time/$multiple
            );
        }
        return $this; //chainability
    }

    /**
     * Returns all the results
     * @return array $results
     */
    public function get_results()
    {
        return $this->_results;
    }
}

$benchmark = new Benchmark();

$benchmark->time( 'Closure test', function () {
    $fn = function($item) { return $item; };
    $fn('test');
}, true);

$benchmark->time( 'Anonymous test', function () {
    $fn = create_function( '$item', 'return $item;' );
    $fn('test');
}, true);

$benchmark->time( 'Closure direct', function () {
    $test_array = array('test', 'test', 'test', 'test', 'test' );
    $test_array = array_map( function ( $item ) { return $item; }, $test_array );
}, true);

$benchmark->time( 'Closure stored', function () {
    $test_array = array('test', 'test', 'test', 'test', 'test' );
    $fn = function ( $item ) { return $item; };
    $test_array = array_map( $fn, $test_array );
}, true);

$benchmark->time( 'Anonymous direct', function () {
    $test_array = array('test', 'test', 'test', 'test', 'test' );
    $test_array = array_map( create_function( '$item', 'return $item;' ), $test_array );
}, true);

$benchmark->time( 'Anonymous stored', function () {
    $test_array = array('test', 'test', 'test', 'test', 'test' );
    $fn = create_function( '$item', 'return $item;' );
    $test_array = array_map( $fn, $test_array );
}, true);

var_dump($benchmark->get_results());
请参见此基准:

<?php
$iter = 100000;


$start = microtime(true);
for ($i = 0; $i < $iter; $i++) {}
$end = microtime(true) - $start;
echo "Loop overhead: ".PHP_EOL;
echo "$end seconds".PHP_EOL;

$start = microtime(true);
for ($i = 0; $i < $iter; $i++) {
    $fn = function($item) { return $item; };
    $fn('test');
}
$end = microtime(true) - $start;
echo "Lambda function: ".PHP_EOL;
echo "$end seconds".PHP_EOL;


$start = microtime(true);
for ($i = 0; $i < $iter; $i++) {
    $fn = create_function( '$item', 'return $item;' );
    $fn('test');
}
$end = microtime(true) - $start;
echo "Eval create function: ".PHP_EOL;
echo "$end seconds".PHP_EOL;
现在,非常有趣的是,如果将函数声明放在for循环之外:

Loop overhead: 
0.0057950019836426 seconds
Lambda function: 
0.030204057693481 seconds
Eval create function: 
0.040947198867798 seconds

为了回答您最初的问题,将lambda函数赋给变量和简单地使用它之间没有区别。除非您不止一次地使用它,否则在这种情况下,为了代码清晰起见,使用变量会更好

5.132770538301E-6不会比1.6745710372925E-5慢4倍;它大约快3倍。你看错数字了。似乎在所有结果中,闭包始终比
create\u函数

快,这并不让我太惊讶,因为这些匿名函数实际上是实例。首先,您的基准代码虽然令人印象深刻,但本身可能会产生开销。我总是建议在for循环中运行代码多次迭代,测量整个循环所用的时间。当你进入10^-6范围时,时间会变得奇怪。你意识到5.132770538301E-6比1.6745710372925E-5小得多吗?@user102008哇,我真不敢相信我错过了!这确实是真的,在对代码进行了一点调整之后,现在它给了我一个时间,没有指数作为字符串!是否要将其添加为答案,以便将其标记为已接受?我想您缺少的是,我正在对循环中的所有内容进行计时,因此没有添加循环开销。使用
mircotime()
对此类排序事件进行计时时,会变得非常不准确。即使计算了循环开销,您也可以清楚地看到这些函数需要花费预期的时间,执行
eval()
的任何操作都会比较慢。
array
  0 => 
    array
      'test' => string 'Closure test' (length=12)
      'iterations' => int 10000
      'time' => float 5.4110765457153E-6
  1 => 
    array
      'test' => string 'Anonymous test' (length=14)
      'iterations' => int 10000
      'time' => float 1.6784238815308E-5
  2 => 
    array
      'test' => string 'Closure direct' (length=14)
      'iterations' => int 10000
      'time' => float 1.5178990364075E-5
  3 => 
    array
      'test' => string 'Closure stored' (length=14)
      'iterations' => int 10000
      'time' => float 1.5463256835938E-5
  4 => 
    array
      'test' => string 'Anonymous direct' (length=16)
      'iterations' => int 10000
      'time' => float 2.7537250518799E-5
  5 => 
    array
      'test' => string 'Anonymous stored' (length=16)
      'iterations' => int 10000
      'time' => float 2.8293371200562E-5
<?php
$iter = 100000;


$start = microtime(true);
for ($i = 0; $i < $iter; $i++) {}
$end = microtime(true) - $start;
echo "Loop overhead: ".PHP_EOL;
echo "$end seconds".PHP_EOL;

$start = microtime(true);
for ($i = 0; $i < $iter; $i++) {
    $fn = function($item) { return $item; };
    $fn('test');
}
$end = microtime(true) - $start;
echo "Lambda function: ".PHP_EOL;
echo "$end seconds".PHP_EOL;


$start = microtime(true);
for ($i = 0; $i < $iter; $i++) {
    $fn = create_function( '$item', 'return $item;' );
    $fn('test');
}
$end = microtime(true) - $start;
echo "Eval create function: ".PHP_EOL;
echo "$end seconds".PHP_EOL;
Loop overhead: 
0.011878967285156 seconds
Lambda function: 
0.067019939422607 seconds
Eval create function: 
1.5625419616699 seconds
Loop overhead: 
0.0057950019836426 seconds
Lambda function: 
0.030204057693481 seconds
Eval create function: 
0.040947198867798 seconds