测试环境为 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])
