本篇為 PHP 系列
一支程式的效能有幾個重要的指標,其中一個是記憶體用量,之前的文章中有介紹過如何衡量記憶體用量,而今天這一篇文章要介紹的則是另一個重要指標:執行時間。
要如何測量程式的執行時間?其實原理很簡單,只要記錄開始時間跟結束時間,然後以後者減去前者就好了。
在 PHP 中有 time()
、microtime
及 hrtime
可以用來取得目前時間,而這三者的主要差別在於時間的精細度。
time()
time()
回傳的是當下的 Unix timestamp
,單位是秒。Unix timestamp
,其代表的數字是 1970/01/01 00:00:00 GMT+0
到目前為止所累計的秒數。例如:
print(time()); // 輸出 : 1668667291
因此要計算某段程式的執行時間可以這麼做:
$startTime = time(); // 開始時間
for($i = 0; $i < 100000; $i++){
$i++;
}
$endTime = time(); // 結束時間
print($endTime - $startTime); // 0
如上面的的例子,因為簡單的加法對 PHP 來說是非常快速的運算(其實對任何語言應該都是吧),所以跑 100,000 次所需的時間不到 1 秒,因此結果是 0 秒。如果我們讓次數增加到 1,000,000,000 次:
$startTime = time(); // 開始時間
for($i = 0; $i < 1000000000; $i++){
$i++;
}
$endTime = time(); // 結束時間
print($endTime - $startTime); // 輸出: 1
現在我們看到結果是 1 秒,可以看到簡單的加法跑了十億次才花了 1 秒多。
看到這邊我們會發現一個小問題,很多程式其實並不會執行超過一秒,如果都使用 time()
來測量的話結果都會是 0,那就比較不出差異了,總不能每次都讓他們跑一千次吧?因此只能用秒來計算時間是不夠用的,精密度不夠,也就是因為這樣,其實大部分的時候我會使用 microtime()
來做測量。
microtime()
microtime()
的一樣回傳的是 Unix Timestamp,但精準度會來到微秒,如果不知道微秒的大小,這邊稍微科普一下,微秒是 10^-6
秒,也就是 0.000001 秒,而毫秒則是 10^-3
秒,也就是 0.001 秒。
而 microtime()
需要一個參數,這個參數決定是否回傳浮點數,預設是 fasle
,會回傳字串,若傳 true
則會回傳浮點數。例如:
<?php
var_dump(microtime(false)); // 輸出: string(21) "0.71466000 1668671090"
var_dump(microtime(true)); // 輸出: float(1668671090.714438)
習慣上我們會帶 true
使用浮點數,這樣計算上比較方便。那可以看到上面的範例的回傳值,整數的部分仍然是秒數,小數點以下六位數則是準確到微秒。現在我們實際拿 microtime()
來進行測量:
<?php
$startTime = microtime(true); // 開始時間
for($i = 0; $i < 100000; $i++){
$i++;
}
$endTime = microtime(true); // 結束時間
print(round($endTime - $startTime, 6)); // 輸出: 0.000305 (秒)
print(PHP_EOL);
print(round(($endTime - $startTime) * 1000000)); // 轉換成微秒,輸出: 305 (微秒)
這邊我們一樣用前面的簡單加法,跑了十萬次,這一次我們可以看到實際的執行時間了,以這次為例子,跑了 0.000305秒,也就是 305 微秒。
hrtime()
最後,如果我們不滿足於微秒的話,在 PHP 7.3 以後,提供了 hrtime()
,它回傳的的不是 UNIX TIMESTAMP,而是系統的高解析度時間 (high resolution time),它的精準度來到了奈秒 (10^-9
秒)。
hrtime()
用法與 microtime()
類似,也需要一個參數,這個參數決定是否回傳數字,而這個回傳的這個數字本身就是奈秒,如果傳 false
則會回傳一個陣列,格式是 [秒, 奈秒]
。一樣會習慣傳 true
方便計算。
<?php
$startTimeMi = microtime(true); // micro 開始時間
$startTimeHr = hrtime(true); // hr 開始時間
for($i = 0; $i < 100000; $i++){
$i++;
}
$endTimeHr = hrtime(true); // hr 結束時間
$endTimeMi = microtime(true); // micro 結束時間
var_dump(round($endTimeMi - $startTimeMi, 6)); // 輸出: 0.000314 秒
var_dump($endTimeHr - $startTimeHr); // 輸出: 299984 奈秒
而 hrtime
除了精準度可以到達奈秒以外,根據定義,hrtime
可以取得的時間是更精準而不受其他因素影響的,因此非常適合拿來衡量程式的表現,PHP 官方其實也建議使用 hrtime() 來做效能衡量。個人目前是以 microtime 為主,未來也許會跟進採用 hrtime。
參考
本篇為 PHP 系列