开放的编程资料库

当前位置:我爱分享网 > PHP教程 > 正文

基准测试动态函数/方法调用

为了响应ScottJohnson关于可变函数的建议,我决定运行一些基准测试。

编写基准很容易。然而,我看到很多博客条目和邮件列表帖子都在问,“哪个更快?”我的第一个想法总是,“为什么他们不测试并找出答案?”如果我对某些东西如何工作有疑问,我会打开一个临时文件,开始编码,然后运行代码。这是最简单的学习方法。此外,它还教您将事物分解成可管理、可测试的块,并且此代码通常构成以后单元测试的基础。

回到基准测试。Scott问道,“call_user_funccall_user_func_array和变量函数语法(即$function_name())之间真的有区别吗?”

简短的回答:绝对。长答案?继续阅读。

首先,call_user_func()call_user_func_array()的区别。call_user_func()当您确切知道您调用的函数或方法需要多少个参数时非常方便,并且即使实际回调发生变化也不会发生变化。这会发挥作用的实例包括调用已建立接口的观察者,并且您知道这些观察者上的被调用方法将始终具有相同数量的参数。此外,使用call_user_func(),您可以准备好单独传递每个参数:

call_user_func($callback, $arg1, $arg2, $arg3);

但是,如果您不知道自己有多少个参数,或者参数的数量因调用而异怎么办?您将如何构建对call_user_func()的调用?这就是call_user_func_array()发挥作用的地方。基本上,call_user_func_array()只需要两个参数:回调和传递给回调的参数数组:

$callback = 'myFunc';
$args = ('me', 'myself', I');
call_user_func_array($callback, $args);

这被称为:

myFunc('me', 'myself', 'I');

这什么时候方便?当我开发Cgiapp2时,我知道模板引擎通常为其assign()方法(将变量分配给模板)采用可变数量的参数——一个键和一个值,一个值,或一个关联例如,键/值对数组。由于我事先无法知道参数是什么,我将主题设置为允许可变数量的参数,然后将它们全部传递给观察者:

class myClass
{
    // observer callback
    public static $observer;

    function subject()
    {
        // get arguments
        $args = func_get_args();

        // call observer with all arguments
        call_user_func_array(self::$observer, $args);
    }
}

那么,现在,动态函数呢?这些很方便,但可能有些限制:您可以将它们与对象实例方法或定义的函数一起使用,但它们不能与静态方法一起使用。如果您尝试$class::$method,您将收到意外的T_PAAMAYIM_NEKUDOTAYIM解析器错误。在这种情况下,您必须使用call_user_func()call_user_func_array()

一切都已完成,让我们来回答Scott的问题:“以这种或另一种方式进行有效率上的好处吗?”

从纯执行时间的角度来看,是的。我运行了以下代码:

class myTest
{
    public static function test()
    {
        return true;
    }

    public function testMe()
    {
        return true;
    }
}

function testMe()
{
    return true;
}

$o = new myTest();

$function = 'testMe';

echo 'Straight function call: ';
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    testMe();
}
$end = microtime(true);
$elapsed = $end - $start;
echo $elapsed, ' secs', "\n";

echo 'Dynamic function call: ';
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    $function();
}
$end = microtime(true);
$elapsed = $end - $start;
echo $elapsed, ' secs', "\n";

echo 'call_user_func function call: ';
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    call_user_func($function);
}
$end = microtime(true);
$elapsed = $end - $start;
echo $elapsed, ' secs', "\n";

echo 'call_user_func_array function call: ';
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    call_user_func_array($function, null);
}
$end = microtime(true);
$elapsed = $end - $start;
echo $elapsed, ' secs', "\n";

echo 'Straight static method call: ';
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    myTest::test();
}
$end = microtime(true);
$elapsed = $end - $start;
echo $elapsed, ' secs', "\n";

echo 'call_user_func static method call: ';
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    call_user_func(array('myTest', 'test'));
}
$end = microtime(true);
$elapsed = $end - $start;
echo $elapsed, ' secs', "\n";

echo 'call_user_func_array static method call: ';
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    call_user_func_array(array('myTest', 'test'), null);
}
$end = microtime(true);
$elapsed = $end - $start;
echo $elapsed, ' secs', "\n";

echo 'Straight method call: ';
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    $o->testMe();
}
$end = microtime(true);
$elapsed = $end - $start;
echo $elapsed, ' secs', "\n";

echo 'call_user_func method call: ';
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    call_user_func(array($o, 'testMe'));
}
$end = microtime(true);
$elapsed = $end - $start;
echo $elapsed, ' secs', "\n";

echo 'call_user_func_array method call: ';
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    call_user_func_array(array($o, 'testMe'), null);
}
$end = microtime(true);
$elapsed = $end - $start;
echo $elapsed, ' secs', "\n";

在我的机器上,它给了我这些结果:

Straight function call: 0.909409046173 secs
Dynamic function call: 1.14596605301 secs
call_user_func function call: 1.48889017105 secs
call_user_func_array function call: 2.02058911324 secs
Straight static method call: 0.789363861084 secs
call_user_func static method call: 4.42607593536 secs
call_user_func_array static method call: 2.98122406006 secs
Straight method call: 1.10703587532 secs
call_user_func method call: 2.71344089508 secs
call_user_func_array method call: 2.56111383438 secs

注意:连续运行几次会产生略有不同的结果;解释将基于运行几次。

  • 动态函数调用比直接调用稍慢(前者有一个额外的解释层来确定要调用的函数
  • call_user_func()大约是50%较慢,并且call_user_func_array()比直接函数调用慢大约100%。
  • 静态和常规方法调用大致等同于函数调用
  • call_user_func()通常比call_user_func_array()慢,而且较快的操作通常至少是直接调用的执行时间的两倍。

从纯粹的性能角度来看,call_user_func()call_user_func_array()是性能消耗大户。然而,从开发人员的角度来看,它们可以节省大量时间和麻烦:它们可以让您编写灵活的Observer/Subject模式或Decorator模式,这两者都可以使您的类和应用程序更加灵活和可扩展,从而节省您的编码时间晚些。

未经允许不得转载:我爱分享网 » 基准测试动态函数/方法调用

感觉很棒!可以赞赏支持我哟~

赞(0) 打赏