在 PHP 性能调优的过程中,准确测量脚本的执行时间和资源消耗是非常重要的。常见的做法是结合 microtime() 和 getrusage() 两个函数来监控脚本运行时间和系统资源使用情况。然而,这种方法真的可靠吗?本文将详细探讨这两者的使用方式及其准确性。
microtime() 返回当前 Unix 时间戳的微秒数部分,常用于高精度计时。典型用法是先在脚本开始时调用一次,结束时再调用一次,两者相减即可得到脚本执行的时间。
<?php
$start = microtime(true);
// 模拟耗时操作
usleep(500000); // 500毫秒
$end = microtime(true);
$elapsed = $end - $start;
echo "脚本执行时间: {$elapsed} 秒\n";
?>
这种方式的优点是简单直接,且精度足够衡量大部分 PHP 脚本性能。
getrusage() 返回当前进程资源使用情况的数组,包括用户CPU时间、系统CPU时间、内存使用情况等。常用于更细粒度的性能分析。
<?php
$usage_start = getrusage();
// 模拟耗时操作
usleep(500000);
$usage_end = getrusage();
$user_cpu_start = $usage_start["ru_utime.tv_sec"] + $usage_start["ru_utime.tv_usec"] / 1e6;
$user_cpu_end = $usage_end["ru_utime.tv_sec"] + $usage_end["ru_utime.tv_usec"] / 1e6;
$user_cpu_time = $user_cpu_end - $user_cpu_start;
echo "用户态CPU时间: {$user_cpu_time} 秒\n";
?>
通过计算用户态CPU时间差,我们可以知道 CPU 实际处理脚本所用的时间,而非包括等待时间的整体运行时长。
有人会同时使用这两者来判断脚本性能:
用 microtime() 计算总耗时(wall-clock time)
用 getrusage() 计算CPU时间(用户态+系统态)
示例代码:
<?php
$start_time = microtime(true);
$start_usage = getrusage();
// 模拟耗时操作
usleep(500000);
$end_time = microtime(true);
$end_usage = getrusage();
$elapsed_time = $end_time - $start_time;
$user_cpu_start = $start_usage["ru_utime.tv_sec"] + $start_usage["ru_utime.tv_usec"] / 1e6;
$user_cpu_end = $end_usage["ru_utime.tv_sec"] + $end_usage["ru_utime.tv_usec"] / 1e6;
$user_cpu_time = $user_cpu_end - $user_cpu_start;
$system_cpu_start = $start_usage["ru_stime.tv_sec"] + $start_usage["ru_stime.tv_usec"] / 1e6;
$system_cpu_end = $end_usage["ru_stime.tv_sec"] + $end_usage["ru_stime.tv_usec"] / 1e6;
$system_cpu_time = $system_cpu_end - $system_cpu_start;
echo "总耗时: {$elapsed_time} 秒\n";
echo "用户CPU时间: {$user_cpu_time} 秒\n";
echo "系统CPU时间: {$system_cpu_time} 秒\n";
?>
microtime() 可测量真实时间跨度,包含所有等待和阻塞时间。
getrusage() 反映CPU实际处理时间,能剔除等待I/O等时间,更真实地体现脚本对CPU资源的占用。
两者结合,可以较全面地了解脚本执行效率及系统负载。
getrusage() 并非所有操作系统都支持,Windows 系统上的 PHP 就没有完整支持此函数。
getrusage() 只测量当前进程资源,无法涵盖外部调用或子进程的资源消耗。
脚本中含有大量I/O等待或网络请求时,CPU时间与真实耗时差距较大,getrusage() 反映不出I/O瓶颈。
microtime() 受系统时钟精度影响,极短时间的测量可能不准确。
对于 CPU 密集型的 PHP 脚本,结合两者测量能提供较准确的性能信息。
对于 I/O 密集型脚本,单用 getrusage() 不足以反映整体性能,microtime() 更重要。
建议结合其他性能工具(如 Xdebug、Blackfire 等)进行综合分析。
使用 getrusage() 时注意兼容性问题,特别是在跨平台环境下。
getrusage() 和 microtime() 各有千秋,结合使用确实能更细致地评估 PHP 脚本性能。但是否靠谱,取决于具体使用场景、脚本性质以及测试环境。它们是性能分析的基础工具,而非万能的银弹。只有结合业务特点和更多性能指标,才能科学地判断和优化脚本性能。