測試環境為 apple m1
測試的 php 版本為 8.0.0, 對比的版本為 7.2.34,golang 1.15.6 amd64 with rosetta 2
php 通過 homebrew 安裝,當前 homebrew 已經支持 apple m1。
golang 為官網下載的安裝包。
測試結果如表格中所示:
| 語言 | 耗時 | 性能分數(越高越好) |
| php-8.0.0 | 2.3733 | 4.17 |
| php-8.0.0 with opcache enabled | 2.0988 | 4.72 |
| php-7.2.34 | 2.8660 | 3.46 |
| php-7.2.34 with opcache enabled | 2.5066 | 3.95 |
| golang-1.15.6 am64 with rosetta2 | 0.0637 | 155.55 |
golang 無疑擁有最快的性能。因此目前來看,就算有 jit 加持,php 依然是和性能沒有什么關系的一種工具。
測試過程
考慮到 jit 的特性,對重復執行的代碼敏感,對 IO 不敏感,我實現了一段快排算法來測試,快排的 partition 函數會被反復執行,正好考驗 JIT 的效能。
1 function qsort(&$nums, $from, $to) { 2 if ($from >= $to) 3 return; 4 $mid = partition($nums, $from, $to); 5 qsort($nums, $from, $mid - 1); 6 qsort($nums, $mid + 1, $to); 7 } 8 9 function partition(&$nums, $from, $to) { 10 $pivot = $nums[$from]; 11 $i = $from + 1; 12 $j = $to; 13 while (true) { 14 while ($i < $to && $nums[$i] < $pivot) { 15 $i++; 16 } 17 18 while ($j > $from && $nums[$j] > $pivot) { 19 $j--; 20 } 21 22 if ($i >= $j) { 23 break; 24 } 25 26 $t = $nums[$i]; 27 $nums[$i] = $nums[$j]; 28 $nums[$j] = $t; 29 30 $i++; 31 $j--; 32 } 33 34 $t = $nums[$j]; 35 $nums[$j] = $pivot; 36 $nums[$from] = $t; 37 38 return $j; 39 }
我用程序實現生成了幾個隨機亂序后的數字的文本文件,num-10.txt 即表示文件內包含 10 個亂序后的數字。生成程序在文末附錄中列出。
因為 apple m1 非常快,我需要 100 萬個數字。
運行 php-8.0.0:
$ php8 qsort.php num-100w.txt
JIT is disabled
time cost: 2.3733279705048
因為 jit 僅支持 x86 平台,因此 JIT 無法在 apple m1 上打開,但即使只打開 opcache,也會看到有性能提升:
$ php8 -d opcache.enable_cli -d opcache.jit_buffer_size=100m -d opcache.jit=1255 qsort.php num-100w.txt
JIT is disabled
time cost: 2.0988318920135
使用 php-7.2.34 運行:
$ php qsort.php num-100w.txt
JIT is disabled
time cost: 2.8660459518433
使用 php-7.2.34 with opcache
$ php -d opcache.enable_cli qsort.php num-100w.txt
JIT is disabled
time cost: 2.5065989494324
golang 的版本如下
func qsort(nums []int, lo int, hi int) {
if lo >= hi {
return;
}
mid := partition(nums, lo, hi);
qsort(nums, lo, mid - 1);
qsort(nums, mid + 1, hi);
}
func partition(nums []int, lo int, hi int) int {
i := lo + 1;
j := hi;
pivot := nums[lo];
for {
for (i < hi && nums[i] < pivot) {
i++;
}
for (j > lo && nums[j] > pivot) {
j--;
}
if (i >= j) {
break;
}
nums[i], nums[j] = nums[j], nums[i];
i++;
j--;
}
nums[lo], nums[j] = nums[j], nums[lo];
return j;
}
golang 用時是令人發指的少:
$ go run qsort.go num-100w.txt
time cost 0.063744
為了試驗 php-8.0 打開 JIT 后的效果,我找來了一台 x86 的雲服務器試驗,這台雲服比 apple m1 性能差很多。
關閉 JIT
JIT is disabled
time cost: 31.630923986435
打開 JIT
JIT is enabled
time cost: 13.33647108078
x86 上打開 JIT 能有顯著的提升 57.8% 的性能提升。
但盡管如此,php 依然和性能不搭嘎,追求性能還是要用更適合的工具。
附錄-1
隨機數生成工具
使用方法:python3 gen-nums.py <亂序數字的個數>
例如:python3 gen-nums.py 1000000 > num-1m.txt # 生成 100 萬個亂序的數字
1 import random 2 import sys 3 4 DEFAULT_BOUND = 100 5 6 if len(sys.argv) < 2: 7 print('default num of 100 is used', file=sys.stderr) 8 bound = DEFAULT_BOUND 9 else: 10 bound = int(sys.argv[1]) 11 if bound <= 3: 12 raise ValueError('must > 3') 13 print('{0} nums will be generated'.format(bound), file=sys.stderr) 14 15 nums = list(range(1, bound + 1)) 16 random.shuffle(nums) 17 for n in nums[0:-1]: 18 print(n, end = ', ') 19 20 print(nums[-1:][0])
