最近关于PHP7和HHVM的性能对比,成为了一个热点的争议话题,大家都在讨论和关注哪一个才是PHP性能提升的未来。
HHVM是一个开源的PHP虚拟机,使用JIT的编译方式以及其他技术,让PHP代码的执行性能大幅提升。据传,可以将当前版本的原生PHP代码提升5-10倍的执行性能。
HHVM起源于Facebook公司,Facebook早起的很多代码是使用PHP来开发的,但是,随着业务的快速发展,PHP执行效率成为越来越明显的问题。为了优化执行效率,Facebook在2008年就开始使用HipHop,这是一种PHP执行引擎,最初是为了将Fackbook的大量PHP代码转成 C++,以提高性能和节约资源。使用HipHop的PHP代码在性能上有数倍的提升。后来,Facebook将HipHop平台开源,逐渐发展为现在的HHVM。
1. PHP为什么慢?
PHP的慢是相对于C/C++级别的语言来说,事实上,PHP语言最初的设计,就不是用来解决计算密集型的应用场景。我们可以这样粗略理解为,PHP为了提升开发效率,而牺牲了执行效率。
我们知道PHP一个很大的特点,就是弱类型特性,也就是说,我可以随意定义一个变量,然后给它随意赋值为各种类型的数据。以一个int整型数字为例子,在C语言中:
int num = 200; // 通常是4字节
但是,如果是PHP定义了一个同样的变量,实际对应的存储结构则是:
这个结构体将会占据远比C变量多得多的内存,PHP中定义方式如下:
$a = 200;//这变量将实际占用对比C变量很多倍的存储空间。
其实对PHP来说,无论存储什么类型的数据,都是用上述“通杀”的结构体实现。为了兼容PHP程序员的变量类型“乱入”,PHP做到了对开发者的友好,但是对执行引擎很残酷。单个变量内存消耗可能还不明显,一旦用到PHP的数组等,则复杂度指数上升(数组的实现是HashTable)。然后,Zend引擎执行时,将这些PHP代码编译为opcode(PHP的中间字节码,格式有点类似于汇编),由Zend引擎逐行解释执行。
无论是字符串的连接操作,还是数组的简单修改等,几乎都是“PHP程序员一句话,Zend引擎跑断腿”的节奏。因此,同样的操作,对比C来说,PHP消耗了更多的CPU和内存等系统资源。除此之外,还有内存自动回收、变量类型判断等等,都会增加系统资源的消耗。
例如,我用纯PHP实现的快速排序函数和原生sort函数,排序10000个整型数字,来做一个耗时对比,结果如下:
原生的sort耗时3.44 ms,而我们自己实现的PHP函数sort则是68.79 ms。我们发现,两者执行效率差距巨大。我的测试方式,是计算函数执行前后的时间间隔,而不是整个PHP脚本从启动到结束的时间。PHP脚本启动和关闭过程,本身有着一系列的初始化和清理工作,也会占据不少的耗时。
通常情况下,PHP执行效率的排行是:
在一般情况下,我们并不推荐用过PHP实现逻辑复杂计算类型的功能,尤其是Web系统流量比较大的场景下。因此,PHP程序员应该对PHP的各种原生函数和各类拓展有一个比较广泛的了解,在具体的功能实现场景中,寻求更原生的解决方案(原生接口或者拓展),而不是自己写一堆复杂的PHP代码来实现这类型功能。
如果有足够的PHP拓展开发实力,将这类型业务功能重写为一个PHP拓展,也会大幅提升代码的执行效率。这是一个非常不错的方式,也被广泛应用PHP优化中。但是,自己编写的PHP业务拓展的缺点也很明显:
实际上,在互联网一线企业中,更常见的解决方案,并非增加PHP拓展,而用C/C++独立写一个服务server,然后PHP通过socket和服务server通信来完成业务处理,并不将PHP本身和业务耦合在一起。
不过,Web服务大部分的性能瓶颈都在网络传输和其他服务server的耗时上(例如MySQL等),PHP执行的耗时在整体耗时的占用比例非常小,所以从业务角度来说,影响可能并不明显。
2. HHVM提升PHP执行性能的方式
HHVM提升PHP性能的途径,采用的方式就是替代Zend引擎来生成和执行PHP的中间字节码(HHVM生成自己格式的中间字节码),执行时通过JIT(Just In Time,即时编译是种软件优化技术,指在运行时才会去编译字节码为机器码)转为机器码执行。Zend引擎默认做法,是先编译为opcode,然后再逐条执行,通常每条指令对应的是C语言级别的函数。如果我们产生大量重复的opcode(纯PHP写的代码和函数),对应的则是Zend多次逐条执行这些C代码。而JIT所做的则是更进一步,将大量重复执行的字节码在运行的时候编译为机器码,达到提高执行效率的目的。通常,触发JIT的条件是代码或者函数被多次重复调用。
普通的PHP代码,因为无法固定变量的类型,需要额外添加判断类型的逻辑代码,这样PHP代码是不利于CPU执行和优化的。因此,HHVM通常需要用到Hack写法(为了兼容某种特性而额外添加的技巧性质的代码)的PHP代码来“配合”,就是为了让变量类型固定,方便虚拟机编译执行。PHP追求以一种形式来容纳一切类型,而Hack则可以将被容纳的一切标记上确定的类型。
PHP代码的Hack写法的例子:
上面的例子中,PHP代码主要被添加上了变量类型。Hack写法的总体方向,就是将之前“动态”的写法变为“静态”的写法,来配合HHVM。
HHVM因为它的高性能而吸引了不少人的关注,一些一线互联网公司也开始跟进使用。从纯语言执行性能测试结果来看,HHVM领先了开发中的PHP7版本不少。
不过,从具体业务场景来看,HHVM和PHP7的差距并没有那么大,以WordPress开源博客首页为测试场景的结果中,他们目前的差距并不明显。
但是,PHP7目前还在开发中,就已经可用的技术方案来看,目前的HHVM略胜一筹。不过,HHVM的部署和应用都存在一些的问题:
HHVM毕竟是一个相对比较新的开源项目,发展到成熟仍然需要一定时间。
PHP长期以来饱受批评的性能问题,将会在这个版本得到大幅度的改善。版本中间没有PHP6哈,据说,是因为这个版本曾经立过项目,后来大部分功能都在5.x的版本里实现了,为了避免混淆,下一个大版本直接就是PHP7。(几年以前,我还看到过关于PHP6的书籍。)
1. PHP7的介绍
虽然PHP7的正式版本可能要到2015年的10月份才发布,不过明年6月份应可以看见一个测试版本了,之后是3-4个月的质量保证。
PHP社区的项目计划如下:
因为项目仍然处于开发中的原因,从表格中,可以看见的特性描述都比较模糊。肯定有更多的其他特性,只是尚未公布。下面的这些,是从PHP社区看见的,因为PHP7是一个开发中的项目,下面的这些也不一定准确,不过,不妨碍我们一起来看看。
上面的特性中,最令人期待的就是PHPng的性能优化,PHP社区已经放出了一些性能的测速数据。从数据上看,PHPng的执行性能比起项目启动之初,已经有接近1倍的提升。这个成绩已经非常不错,况且,最关键的是PHP7的优化计划还有很多尚未完成。等到都全部完成了,相信我们可以看见一个性能更高的PHP7。
这测速数据是来自于PHP社区(wiki.php.net/phpng),截取了一部分的数据:
对其当前PHP5.6版本,PHPNG的10月份性能提升已经非常明显了:
简单翻译下:
2. PHP的弱类型争议
PHP被争议的特点很多,但是随着语言版本的发布和完善,功能和特性方面的批评开始变少了。但是,PHP的“弱类型”特性,却明显受到更多的争议,从HHVM通过Hack的方式直接“去掉”了“弱类型”特性可以看出,HHVM并不喜欢“弱类型”特性。然而,在我们很多PHP程序员的眼中,这却是PHP的重要优点之一。PHP里的变量被设计得随性和飘逸,海纳百川,一切皆可包容,不是让语言显得更为简单吗?
实际上,有些人认为它是个严重的问题,对于“弱类型”的批评观点大致如下:
他们认为,这些都不符合“所见即所得”的简单性,而语法严谨的语言更高效率,也更容易“理解”。
受到类似批评的还有Javascript等语言,因为它在这个问题上的表现是一样的。但是,一门语言最终被大规模使用,必然有它们的道理。PHP成为Web服务开发的首选脚本语言,Javascript则直接称霸Web前端领域,能走到这一步都不可能是偶然因素,开发者们用脚投票选择了它们。编程语言是人类和机器沟通的桥梁,终极追求是实现“人人皆可编程”的宏伟目标。
纵观语言发展历史,从0和1的机器码开始,到汇编语言,然后到C语言,再到动态脚本语言PHP。执行效率呈指数下降,但是,学习门槛也呈指数降低。PHP语言不仅屏蔽了C的内存管理和指针的复杂性,而且更进一步屏蔽了变量类型的复杂性。提升了项目开发的效率,降低了学习的门槛,但同时牺牲了一定的执行性能。然后,HHVM的Hack给我们一种“回归原始”的感觉,重新引入了变量的复杂性。当然,不同的语言解决不同场景下的问题,并不能够一概而论。
HHVM对PHP的性能提升,让人眼前一亮,而磨刀霍霍的PHP7则让人万分期待。两者都是极其优秀的开源项目,都在不断前进和发展中。就目前而言,因为距离PHP7正式版的发布还有比较长的一段时间,所以当前性能优化方案的首选当然是HHVM。不过,就我个人而言,我比较看好PHP7,因为它更能做到PHP代码的向下兼容。如果两者性能相差不大,我会选择简单的那个。
推荐教程:《php视频教程》
Atas ialah kandungan terperinci 观赏PHP7和HHVM的性能之争. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!