我该如何测量用PHP编写的代码的速度?

128

如何判断多个执行相同任务的类中哪一个执行速度更快?是否有软件可以测量?


只需在Linux中使用time命令。 - Nabi K.A.Z.
10个回答

219

你至少有两种解决方法:

第一种是使用microtime(true)在代码块前后获取执行时间;其他答案已经提到了并给出了示例,所以我就不多说了。

如果你想要对几个指令进行基准测试,这是一个不错的解决方案;比如比较两种类型的函数 -- 最好做成数千次,以确保任何“扰动因素”都被平均掉。

例如,如果你想知道序列化一个数组需要多长时间:

$before = microtime(true);

for ($i=0 ; $i<100000 ; $i++) {
    serialize($list);
}

$after = microtime(true);
echo ($after-$before)/$i . " sec/serialize\n";

这个方案不是完美的,但很有用,而且设置起来不需要花费太多时间。



另一个解决方案,如果你想找出整个脚本中哪些函数占用了大量的时间,可以使用:

  • Xdebug 扩展,用于为脚本生成分析数据
  • 读取分析数据并呈现成易读形式的软件。我知道其中三个:
    • Webgrind;Web界面;在任何Apache+PHP服务器上应该都能用
    • WinCacheGrind;仅适用于Windows
    • KCacheGrind;可能仅适用于Linux和类Linux系统;顺便说一下,这是我最喜欢的那个

要获取分析文件,您必须安装和配置 Xdebug;请查看文档的“分析PHP脚本”页面。

通常我不会默认启用分析器(它会生成相当大的文件,并减慢速度),但是使用一个名为 XDEBUG_PROFILE 的 GET 数据参数的可能性,仅为我需要的页面激活分析。


我的 php.ini 中与分析有关的部分如下:

xdebug.profiler_enable = 0              ; Profiling not activated by default
xdebug.profiler_enable_trigger = 1      ; Profiling activated when requested by the GET parameter
xdebug.profiler_output_dir = /tmp/ouput_directory
xdebug.profiler_output_name = files_names

(阅读文档以获取更多信息)

这个截图来自于 KcacheGrind 中的 C++ 程序:http://kcachegrind.sourceforge.net/html/pics/KcgShot3Large.gif
(来源:sourceforge.net)

使用 PHP 脚本,您将得到完全相同的结果;-)
(我是指使用 KCacheGrind;WinCacheGrind 不如 KCacheGrind 好...)

这使您可以获得应用程序中花费时间的清晰视图——有时它确实有助于定位导致所有事情变慢的函数^^

请注意,Xdebug 计算 PHP 所花费的 CPU 时间;当 PHP 等待来自数据库的答案时(例如),它不在工作;只是等待。 因此,Xdebug 将认为 DB 请求不需要花费太多时间!
这应该在 SQL 服务器上进行分析,而不是 PHP,所以...


希望这有所帮助 :-)
玩得开心!


1
QCacheGrind的Windows版本已经存在 :-) https://sourceforge.net/projects/qcachegrindwin - François Breton

49

对于简单的事情,我会这样做(在PHP中):

$startTime = microtime(true);
doTask(); // whatever you want to time
echo "Time:  " . number_format(( microtime(true) - $startTime), 4) . " Seconds\n";

你还可以使用像http://xdebug.org/这样的分析工具。


2
为了更准确,我建议(a)使用循环并平均时间,(b)为每个要测试的东西使用单独的文件。如果在一个脚本中有多个计时,它们的顺序有时会有所不同。 - DisgruntledGoat

12

我做了一个简单的计时类,也许对某些人有用:

class TimingHelper {

    private $start;

    public function __construct() {
        $this->start = microtime(true);
    }

    public function start() {
        $this->start = microtime(true);
    }

    public function segs() {
        return microtime(true) - $this->start;
    }

    public function time() {
        $segs = $this->segs();
        $days = floor($segs / 86400);
        $segs -= $days * 86400;
        $hours = floor($segs / 3600);
        $segs -= $hours * 3600;
        $mins = floor($segs / 60);
        $segs -= $mins * 60;
        $microsegs = ($segs - floor($segs)) * 1000;
        $segs = floor($segs);

        return 
            (empty($days) ? "" : $days . "d ") . 
            (empty($hours) ? "" : $hours . "h ") . 
            (empty($mins) ? "" : $mins . "m ") . 
            $segs . "s " .
            $microsegs . "ms";
    }

}

使用:

$th = new TimingHelper();
<..code being mesured..>
echo $th->time();
$th->start(); // if it's the case
<..code being mesured..>
echo $th->time();

// result: 4d 17h 34m 57s 0.00095367431640625ms 

您输入错误:应该是 echo,而不是 $echo - SuN

11

2020更新

自我上次回答此问题以来已经过了许多年,我认为这个关于APM领域的信息需要更新。

  • AppDynamics已被思科收购,他们曾经提供的永久免费账户已从他们的网站上撤下。
  • NewRelic将其定价从每台主机每月149美元降至每台主机每月25美元,以与APM市场的新进者Datadog竞争,Datadog提供了每台主机每月31美元的服务。
  • Datadog APM功能仍然简单,有很大的改善空间,但我认为他们会在未来一年内加强和改进这些方面。
  • Ruxit已被Dynatrace收购。毫不意外,因为Ruxit是由Dynatrace前员工构建而成。这使得Dynatrace转变为真正的SaaS模式,效果更好。如果你想要的话,可以告别笨重的Java客户端。
  • 现在也有免费/开源选择。请查看Apache Skywalking,它在中国顶级技术公司中非常流行,还有PinPoint,它提供了一个演示版,你可以在安装之前尝试一下。这两个都需要你自己管理托管,所以准备好启动几个虚拟机并花费一些时间进行安装和配置。
  • 我没有尝试过这些开源APM解决方案的任何一个,因此我没有资格推荐它们,但是我个人管理过为数众多的组织的所有这些APM解决方案,无论是在本地还是在云端部署了数百个应用程序/微服务. 因此,我可以自信地说,如果它们符合你的要求,那么任何供应商都不会错。


最初回答于2015年10月

以下是直接回答您问题的内容

是否有软件可以测量此项任务?

有的,我想知道为什么还没有人提到它。虽然上面提供的答案对于快速检查似乎很好,但从长远来看或对于更大的项目而言并不可扩展。

为什么不使用专门用于此目的及更多功能的应用程序性能监控(APM)工具呢?请查看NewRelic、AppDynamics、Ruxit(均有免费版本),以便监视每个应用程序的执行时间、资源使用情况和吞吐量等指标,甚至方法级别的分析也做得到。


8

如果您想快速测试框架的性能,可以将其放入index.php文件中。

//at beginning
$milliseconds = round(microtime(true) * 1000);

//and at the end
echo round(microtime(true) * 1000) - $milliseconds;

每次执行都会以毫秒为单位获取执行时间。因为微秒在测试框架的情况下并不太有用。


1
这非常简单,而且效果很好。谢谢! - Gavin

5

4

我想分享一个我自己制作的函数,用于测量任何具有最多10个参数的现有函数的速度:

function fdump($f_name='', $f_args=array()){

    $f_dump=array();
    $f_result='';

    $f_success=false;

    $f_start=microtime();
    $f_start=explode(' ', $f_start);
    $f_start=$f_start[1] + $f_start[0];

    if(function_exists($f_name)){

        if(isset($f_args[0])&&is_array($f_args[0])){
            if($f_result=$f_name($f_args)){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[1])){
            if($f_result=$f_name($f_args[0])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[2])){
            if($f_result=$f_name($f_args[0],$f_args[1])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[3])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[4])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[5])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[6])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[7])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5],$f_args[6])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[8])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5],$f_args[6],$f_args[7])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[9])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5],$f_args[6],$f_args[7],$f_args[8])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[10])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5],$f_args[6],$f_args[7],$f_args[8],$f_args[9])){
                $f_success=true;
            }
        }
    }
    $f_end=microtime();
    $f_end=explode(' ', $f_end);
    $f_end=$f_end[1] + $f_end[0];

    $f_time=round(($f_end - $f_start), 4);
    $f_dump['f_success']=$f_success;
    $f_dump['f_time']=$f_time;
    $f_dump['f_result']=$f_result;

    var_dump($f_dump);exit;

    //return $f_result;

}

例子

function do_stuff($arg1='', $arg2=''){
    return $arg1.' '.$arg2;
}

fdump('do_stuff',array('hello', 'world'));

返回
  array(3) {
    ["f_success"]=>
    bool(true)
    ["f_time"]=>
    float(0)            //too fast...
    ["f_result"]=>
    string(11) "hello world"
  }

3

如果可以在Web上下文之外进行测试,我只使用Unix的time命令。


3

Zend Studio内置了使用XDebug或ZendDebugger进行分析的支持。它将分析您的代码,告诉您每个函数花费的时间。这是一个非常好的工具,用于找出您的瓶颈所在。


1

您可以使用基本的方法,例如在操作之前和之后存储时间戳或microtime()来计算所需的时间。这很容易做到,但不是非常准确。也许更好的解决方案是Xdebug,我从未使用过它,但它似乎是我能找到的最知名的PHP调试器/分析器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接