PHP hrtime 函数
上次修改时间:2025 年 5 月 18 日
PHP 中的 hrtime 函数提供高分辨率计时测量,以纳秒为单位返回系统的高分辨率时间。它在 PHP 7.3 中引入,非常适合需要微秒级精度可能不足的精确基准测试和性能测量。
PHP 中的 hrtime
函数提供高分辨率计时,具有纳秒精度,返回总纳秒计数(作为整数)或包含秒和纳秒的数组。它具有单调性,这意味着它不受系统时间变化的影响,使其非常适合性能基准测试、剖析和执行时间优化。为了提高测量精度,应通过多次迭代测试小型操作,同时考虑开销以确保精确的结果。为了更好的可读性,可以将值转换为常用的单位,例如毫秒或秒。
hrtime([ bool $get_as_number ]): mixed
hrtime
函数有一个可选的 $get_as_number
参数。如果设置为 true
,则该函数以整数形式返回当前时间(以纳秒为单位)。如果设置为 false
或省略,则它返回一个包含两个元素的数组:秒和纳秒。
hrtime 的主要特征
- 以整数或秒和纳秒的数组形式返回纳秒。
- 提供比
microtime
更高的精度,并且具有单调性。 - 用于基准测试、剖析和性能优化。
- 多次迭代可提高小型操作的精度。
- 应考虑测量开销以进行精确计时。
- 可以将值转换为毫秒或秒以提高可读性。
hrtime 的基本用法
hrtime
可以通过两种方式调用:不带参数以获取当前时间,或者使用布尔参数以将时间作为数组获取。默认情况下,它将纳秒作为整数返回。
<?php declare(strict_types=1); // Get current time in nanoseconds $time = hrtime(true); echo "Current time: $time nanoseconds\n"; // Get time as an array [seconds, nanoseconds] $timeArray = hrtime(); print_r($timeArray); // Measure time difference $start = hrtime(true); usleep(1000); // Sleep for 1000 microseconds (1ms) $end = hrtime(true); $duration = $end - $start; echo "Slept for: " . ($duration / 1e6) . " milliseconds\n";
这演示了 hrtime
的基本用法。第一个调用以整数形式获取当前时间(以纳秒为单位)。第二个不带参数的调用返回一个包含秒和纳秒的数组。该示例还展示了如何通过计算两个 hrtime(true)
调用的差值来测量代码段的持续时间。
λ php basic_usage.php Current time: 3846251417975 nanoseconds Array ( [0] => 3846 [1] => 251417975 ) Slept for: 1.067367 milliseconds
比较 hrtime 与 microtime
对于精确的计时测量,hrtime
提供了优于 microtime
的几个优势。此示例比较了这两个函数。
<?php declare(strict_types=1); // Using microtime() $startMicro = microtime(true); usleep(100); $endMicro = microtime(true); $microDuration = ($endMicro - $startMicro) * 1e6; // Convert to microseconds // Using hrtime() $startHr = hrtime(true); usleep(100); $endHr = hrtime(true); $hrDuration = ($endHr - $startHr) / 1e3; // Convert to microseconds echo "microtime measured: $microDuration microseconds\n"; echo "hrtime measured: $hrDuration microseconds\n"; // Measure resolution $iterations = 1000; $times = []; for ($i = 0; $i < $iterations; $i++) { $start = hrtime(true); $end = hrtime(true); $times[] = $end - $start; } echo "Minimum resolution: " . min($times) . " nanoseconds\n"; echo "Average resolution: " . array_sum($times)/$iterations . " nanoseconds\n";
这表明 hrtime
通常提供比 microtime
更高的分辨率计时。分辨率测试表明,hrtime
可以测量 microtime
可能无法准确捕捉的非常短的间隔。
λ php comparison.php microtime measured: 16182.18421936 microseconds hrtime measured: 803.9 microseconds Minimum resolution: 0 nanoseconds Average resolution: 63.9 nanoseconds
使用 hrtime 进行基准测试
hrtime
非常适合对代码段进行基准测试。以下是如何正确构建基准测试并计算有意义的统计数据。
<?php declare(strict_types=1); function benchmark(callable $function, int $iterations = 1000): array { $durations = []; // Warm-up (run once to avoid initialization bias) $function(); for ($i = 0; $i < $iterations; $i++) { $start = hrtime(true); $function(); $end = hrtime(true); $durations[] = $end - $start; } $total = array_sum($durations); return [ 'iterations' => $iterations, 'total_ns' => $total, 'avg_ns' => $total / $iterations, 'min_ns' => min($durations), 'max_ns' => max($durations), 'variance' => stats_variance($durations), ]; } function stats_variance(array $values): float { $avg = array_sum($values) / count($values); $sum = 0; foreach ($values as $value) { $sum += ($value - $avg) ** 2; } return $sum / count($values); } // Example benchmark $result = benchmark(function() { // Code to benchmark $array = range(1, 1000); $sum = array_sum($array); }, 10000); echo "Benchmark Results:\n"; echo "Iterations: {$result['iterations']}\n"; echo "Total time: " . ($result['total_ns'] / 1e9) . " seconds\n"; echo "Average: " . ($result['avg_ns'] / 1e6) . " ms\n"; echo "Min: {$result['min_ns']} ns\n"; echo "Max: {$result['max_ns']} ns\n"; echo "Variance: {$result['variance']}\n";
这演示了使用 hrtime
的稳健基准测试方法。基准测试函数多次运行代码,计算统计数据,并包括一个预热运行以考虑初始化成本。方差有助于识别计时的一致性。
λ php benchmarking.php Benchmark Results: Iterations: 10000 Total time: 0.070156 seconds Average: 0.0070156 ms Min: 6300 ns Max: 63800 ns Variance: 4937010.6400005
测量函数执行时间
hrtime
可以精确测量函数执行所需的时间。这是一个用于对任何可调用对象进行计时的可重用函数。
<?php declare(strict_types=1); function measure(callable $function, ...$args): array { $start = hrtime(true); $result = $function(...$args); $end = hrtime(true); return [ 'result' => $result, 'time_ns' => $end - $start, ]; } // Example usage function calculatePrimes(int $limit): array { $primes = []; for ($i = 2; $i <= $limit; $i++) { $isPrime = true; for ($j = 2; $j <= sqrt($i); $j++) { if ($i % $j === 0) { $isPrime = false; break; } } if ($isPrime) { $primes[] = $i; } } return $primes; } $measurement = measure('calculatePrimes', 1000); echo "Found " . count($measurement['result']) . " primes\n"; echo "Took " . ($measurement['time_ns'] / 1e6) . " milliseconds\n";
这展示了如何使用 hrtime
包装任何函数调用以进行精确计时。measure 函数返回结果和所花费的时间,允许您分析性能而不影响函数的操作。
λ php function_timing.php Found 168 primes Took 0.3902 milliseconds
真实世界的剖析示例
以下是如何使用 hrtime
来剖析算法的不同实现,以确定哪个更有效。
<?php declare(strict_types=1); // Two implementations of Fibonacci sequence function fibRecursive(int $n): int { if ($n <= 1) return $n; return fibRecursive($n - 1) + fibRecursive($n - 2); } function fibIterative(int $n): int { if ($n <= 1) return $n; $a = 0; $b = 1; for ($i = 2; $i <= $n; $i++) { $c = $a + $b; $a = $b; $b = $c; } return $b; } // Profile both implementations function profile(string $name, callable $function, int $input): array { $start = hrtime(true); $result = $function($input); $end = hrtime(true); return [ 'name' => $name, 'result' => $result, 'time_ns' => $end - $start, ]; } $input = 30; // Warning: recursive gets very slow with larger numbers $recursive = profile('Recursive', 'fibRecursive', $input); $iterative = profile('Iterative', 'fibIterative', $input); echo "Fibonacci($input) results:\n"; echo "{$recursive['name']}: {$recursive['result']} in " . ($recursive['time_ns'] / 1e6) . " ms\n"; echo "{$iterative['name']}: {$iterative['result']} in " . ($iterative['time_ns'] / 1e6) . " ms\n";
此示例清楚地显示了斐波那契数列的递归和迭代实现之间的性能差异,hrtime
提供了对时间差异的精确测量。
λ php profiling.php Fibonacci(30) results: Recursive: 832040 in 124.234367 ms Iterative: 832040 in 0.005367 ms
最佳实践
要使用 hrtime
获得准确且有意义的结果,请遵循以下最佳实践
<?php declare(strict_types=1); // 1. Always measure multiple iterations for small operations function measureMany(callable $function, int $iterations = 1000): float { $start = hrtime(true); for ($i = 0; $i < $iterations; $i++) { $function(); } $end = hrtime(true); return ($end - $start) / $iterations; } // 2. Account for the measurement overhead $start = hrtime(true); $end = hrtime(true); $overhead = $end - $start; echo "Measurement overhead: $overhead ns\n"; // 3. Use monotonic time for reliable measurements // hrtime() is monotonic by default (unlike microtime()) // 4. Convert units appropriately for readability function formatDuration(int $ns): string { if ($ns < 1e3) return "$ns ns"; if ($ns < 1e6) return round($ns/1e3, 2) . " μs"; if ($ns < 1e9) return round($ns/1e6, 2) . " ms"; return round($ns/1e9, 2) . " s"; } // 5. Run warm-up iterations before measuring function warmup(callable $function, int $iterations = 10): void { for ($i = 0; $i < $iterations; $i++) { $function(); } } // 6. Consider using a benchmarking library for complex scenarios // Example: https://github.com/phpbench/phpbench // 7. Document your measurement methodology /** * Measures database query performance * @param callable $query Should execute and return the query result * @param int $iterations Number of times to run for stable measurement * @return array Contains 'result', 'time_ns', and 'iterations' */ function measureQuery(callable $query, int $iterations = 100): array { warmup($query); $start = hrtime(true); $result = null; for ($i = 0; $i < $iterations; $i++) { $result = $query(); } $end = hrtime(true); return [ 'result' => $result, 'time_ns' => ($end - $start) / $iterations, 'iterations' => $iterations ]; }
这些实践有助于确保您的计时测量准确、可靠且有意义。关键点是测量多次迭代,考虑开销,并正确记录您的方法。
在本文中,我们介绍了在 PHP 中使用 hrtime 的基础知识,包括如何测量执行时间,将其与 microtime
进行比较,以及将其用于基准测试。我们还讨论了用于精确测量和剖析实际场景的最佳实践。
作者
列出所有 PHP 教程。