一直都说phpjava要慢,今天从理论跟实际测试看看php是否真的慢,慢在哪里 一: 运行模式对比

java:一般用java 语言开发的网站项目都是以命令行模式运行,部分可能以可执行文件(.exe)的形式运行;
php:主要以cgi模式运行,部分以cli模式运行,如swoole 拓展;
php cgi 模式下每次请求进来都需要以进程的方式执行php代码,创建进程以及进程切换都需要消耗不少资源;
优化方案:1:FPM 进程池保持一定活跃进程,做到进程重用
2:使用swoole 拓展,将php以cli模式执行,这模式上就跟java类似了;

二: 代码执行模式

java:执行前需要编译为jvm的字节码(不是cpu的字节码),代码执行直接解析字节码或者将字节码编译为机器二进制码后执行
php:每次请求进来都需要经过代码分析->解析->编译opcode->执行的流程,前面3步比起java都是额外的损耗
优化方案:php开启opcache缓存(5.5以后官方自带拓展),可以省去前面3步的重复工作;
php执行流程请参考:PHP执行流程简述

三:语言特性

从整个语言编译执行流程上来看,php经过上面的优化效率应该跟java不相上下才对,下面单从语言上对php 跟java做一次测试;

测试环境:Windows 10 64位 cpu i5 内存8g
java版本:jdk 10
php版本:php 8.0.14
测试功能:用两种语言实现相同数据量(2w个整数)的冒泡排序,对比双方执行时间;

代码如下:

java 代码

public class Test { public static void main(String[] args) { long st=System.currentTimeMillis(); int count=20000;//这个数考虑到php 执行时间,选取了这个,越大对java 越有利 int[] arr=new int[count]; //数组赋值随机数 for (int i=0;i<count;i++){ final double d = Math.random(); arr[i] = (int)(d*count); } System.out.println(“数据生成用时=”+(System.currentTimeMillis()-st)); for(int i=0;i<arr.length-1;i++){ for(int j=0;j<arr.length-1-i;j++){ if(arr[j]>arr[j+1]){ int temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } } System.out.println(“总共耗时=”+(System.currentTimeMillis()-st)); }}

php 代码

<?php/** * Created by PhpStorm. * User: 05 * Date: 2021/12/27 * Time: 10:50 */class Test{ public function msort(){ $arr=[]; $count=20000;//这个数据大了 要运行很久,经过多测测试 2w比较合适 $st=microtime(true); //生成随机数赋值 for ($i=0;$i<$count;$i++){ $arr[$i]=mt_rand(0,$count); } echo “数据生成用时=”.(microtime(true)-$st); for ($i=0;$i<$count-1;$i++){ for ($j=0;$j<$count-1-$i;$j++){ if ($arr[$j]>$arr[$j+1]){ $temp=$arr[$j]; $arr[$j]=$arr[$j+1]; $arr[$j+1]=$temp; } } } echo “总用时=”.(microtime(true)-$st); }}$t=new Test();$t->msort();

结果

java:随机产生2w个整数耗时需要3毫秒,生成数据到排序完2w个数排序需要800毫秒左右,这里测试了多次,时间相差不大

PHP:未开启opcache 跟 jit
生成随机数 耗时:1毫秒多点,完成整个排序耗时:13秒多…

这个结果还是让我大跌眼镜,因为这个代码只是测试 php跟 java的执行效率,php也就编译一次,但是整个效率相差十几倍…

结论:
从上面的分析java 跟php的整个编译执行流程应该是差不多的,这里php 也没有多次的编译,所以只能是php 的ZendVM 虚拟机执行opcode的效率不如 JVM的执行字节码的效率,大概原因是 php是弱类型语言,每次执行opcode 时还需要对变量类型进行判断,无法做到强类型语言那样精确的指令转换 ,但是PHP 8.0后也使用了JIT 及时编译技术;

下面我们打开PHP的JIT 在进行测试一次

结果:总耗时为3秒多,比一开始的13秒确实是质的提升,但跟java 的800毫秒比确实也还有差距

总结:PHP 不管是从执行模式,编译流程,还是从语言执行效率上来说都不比java快,但是通过相应的优化后 PHP也并没有网上说的那么大差距,尤其是现在Web 编程以IO为主要约束的时代,基本上PHP可以做到跟java 媲美的效率,另外PHP 在模块拆分,热更新等项目管理上有得天独到的优势,所以是用java还是PHP得自己根据项目需求理解选择

下面是JVM 虚拟机执行,引用网上总结

Java 虚拟机的运行效率如何?
HotSpot 采用了多种技术来提升启动i性能以及峰值性能,即时编译就是其中最重要的技术之一。即时编译建立再程序符合二八定律的假设,即百分之二十的代码占据了百分之八十的计算资源。
对于占据大部分的不常用的diamagnetic,我们无需耗时将其编译成机器码,而是采取解释执行的方法运行,另一方面,对于仅占小部分的热点代码,可以将其编译成机器码,已达到理想的运行速度
理论上讲,即使编译后的 Java 程序的执行效率是可能超过 C++ 程序的。这是因为与静态编译相比,即时编译用程序的运行时信息,并且能够根据这个信息做出相应的优化。例如我们知道虚方法是用来实现面向对象多态性的。对于一个虚方法调用,尽管它由多个目标方法,但在实际运行中它可能只调用其中的一个。这个信息便可以被即时编译器所利用,来规避虚方法调用的开销,从而达到比静态编译的 C++ 程序更高的性能。
为了满足不同场景的需要,HotSpot 内置了多个即时编译器:C1,C2 和 Graal…至多一引入多个即时编译器,是为了在编译时间和生成代码的执行效率之间进行取舍。C1有叫做 Client 编译器,面向的是对启动性能有要求的客户端 GUI 程序,采用的优化手段相对简单,因此编译时间较短。C2 又叫做 Server 编译器,面向的是对峰值性能又要求的服务器程序,采用的优化手段相对复杂,因此编译时间比较长,但同时生成diamagnetic的执行效率较高。
Java 7 以后,HotSpot 默认采用分层编译的方法:热点方法会首先被 C1 编译,而后热点方法中的热点会进一步被 C2 编译。为了不干扰应用的正常运行,HotSpot 的即时编译是放在额外的编译线程中进行的。HotSpot 会根据 CPU 的数量设置编译线程的数目,并且按 1:2 的比例配置给 C1 及 C2 编译器。
在计算资源充足的情况下,字节码的解释执行和即时编译可同时进行。编译完成后的机器码会在下次调用该方法时启动,以替换原本的解释执行。

php执行流程请参考:PHP执行流程简述

参考文章:https://blog.csdn.net/qq_40488936/article/details/106308182
https://blog.csdn.net/weixin_43814458/article/details/106405207