Java为啥比PHP快?

一直都说php比java要慢,今天从理论跟实际测试看看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

  • 6
    点赞
  • 15
    收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论 1

打赏作者

qq_540616979

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值