PHP 和HHVM 性能之争

PHP语言的排名变化

根据“TIOBE编程语言排行榜”(榜单虽然统计方式有局限,可是仍然不失为一个比较好的参考),2010年PHP最高曾经在世界编程语言中排名第三。可见,PHP语言在PC互联网时代的Web领域可谓叱咤风云,擎天一柱。 
php

5493edc7ccbf3.jpg 

在PHP程序员中,曾经流传着一个段子:前端

某女:你能让这个论坛的人都吵起来,我就跟你吃饭。 
PHP程序员:PHP是世界上最好的语言! 
某论坛炸锅了,各类吵架……  
某女:服了你了,咱们走吧! 
PHP程序员:今天不行,我必定要说服他们,PHP必须是最好的语言。

好了,咱们言归正传,语言自己无分好坏,只是在各自使用的场景中解决不一样的问题。互联网的时代车轮是很快的,随着移动互联网的到来,在短短四年多的时间里,移动端技术发展横扫全球。与此同时,各类语言群雄并起,而昔日辉煌的PHP从原来的编程语言的榜单看,降低到第六位(2014年12月榜单)。因而,唱衰PHP的声音此起彼伏。程序员

5493ee259b467.jpg 

可是,鸟哥(惠新宸,PHP语言开发者之一)在2014年的Qcon分享中有一个数据,全球排名前100万的网站中,81.3%使用的Web服务端脚本语言是PHP,2013年同期是78.3%。也就是说,PHP的在Web服务方面并无减小,只是在移动互联网浪潮中,增长了不少的其余语言技术的应用,进而被稀释了。编程

最近关于PHP7和HHVM的性能对比,成为了一个热点的争议话题,你们都在讨论和关注哪个才是PHP性能提高的将来。数组

HHVM(HipHop Virtual Machine)的起源

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个整型数字,来作一个耗时对比,结果以下:

549bf0056911e.jpg 

原生的sort耗时3.44 ms,而咱们本身实现的PHP函数sort则是68.79 ms。咱们发现,二者执行效率差距巨大。个人测试方式,是计算函数执行先后的时间间隔,而不是整个PHP脚本从启动到结束的时间。PHP脚本启动和关闭过程,自己有着一系列的初始化和清理工做,也会占据很多的耗时。 

549bf02418b55.jpg 


一般状况下,PHP执行效率的排行是:


  1. 最快的是PHP语言结构(isset、echo等),PHP语言的一部分(它们根本不是函数)。

  2. 而后比较快的就是PHP的原生和拓展函数。PHP拓展,基于Zend API之上,用C实现的功能,执行效率和C++/Java是属于同一个数量级的。

  3. 真正慢的就是,咱们经过PHP本身写的代码和函数。例如,假如咱们使用的比较重的纯PHP实现的框架,由于框架自己的模块不少,因此,会明显拖累语言层面的执行效率,同时占据更多的内存。(国内的Yaf框架,以拓展的方式实现,所以执行效率远快于纯PHP写的框架)


549bf058e86bd.jpg 

在通常状况下,咱们并不推荐用过PHP实现逻辑复杂计算类型的功能,尤为是Web系统流量比较大的场景下。所以,PHP程序员应该对PHP的各类原生函数和各种拓展有一个比较普遍的了解,在具体的功能实现场景中,寻求更原生的解决方案(原生接口或者拓展),而不是本身写一堆复杂的PHP代码来实现这类型功能。

若是有足够的PHP拓展开发实力,将这类型业务功能重写为一个PHP拓展,也会大幅提高代码的执行效率。这是一个很是不错的方式,也被普遍应用PHP优化中。可是,本身编写的PHP业务拓展的缺点也很明显:


  1. 拓展开发耗时比较长,需求变动的时候修改也复杂,写得很差可能会影响Web服务稳定性。(例如,在Apache的worker模式下,多线程场景下挂掉,会影响同一个进程下的其余正常子线程。若是是多线程的Web模式,编写拓展还须要支持线程安全)

  2. 拓展在PHP版本升级的时候,可能须要作额外的兼容工做。

  3. 人员变更后的维护和接手成本也比较高。


实际上,在互联网一线企业中,更常见的解决方案,并不是增长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的条件是代码或者函数被屡次重复调用。

549bf09cae043.jpg 

普通的PHP代码,由于没法固定变量的类型,须要额外添加判断类型的逻辑代码,这样PHP代码是不利于CPU执行和优化的。所以,HHVM一般须要用到Hack写法(为了兼容某种特性而额外添加的技巧性质的代码)的PHP代码来“配合”,就是为了让变量类型固定,方便虚拟机编译执行。PHP追求以一种形式来容纳一切类型,而Hack则能够将被容纳的一切标记上肯定的类型。

PHP代码的Hack写法的例子:

549bf0c5cbb6c.jpg 

上面的例子中,PHP代码主要被添加上了变量类型。Hack写法的整体方向,就是将以前“动态”的写法变为“静态”的写法,来配合HHVM。

HHVM由于它的高性能而吸引了很多人的关注,一些一线互联网公司也开始跟进使用。从纯语言执行性能测试结果来看,HHVM领先了开发中的PHP7版本很多。

 

不过,从具体业务场景来看,HHVM和PHP7的差距并无那么大,以WordPress开源博客首页为测试场景的结果中,他们目前的差距并不明显。 

 

可是,PHP7目前还在开发中,就已经可用的技术方案来看,目前的HHVM略胜一筹。不过,HHVM的部署和应用都存在一些的问题:


  1. 服务部署比较复杂,有必定维护成本。

  2. 对PHP原生代码并不是完整支持,PHP拓展也须要作适当的兼容。

  3. HHVM是个新虚拟机,长时间运行有内存泄露。(听说,一线互联网公司在应用这个技术时,是经过本身打Patch的方式解决内存泄露)


HHVM毕竟是一个相对比较新的开源项目,发展到成熟仍然须要必定时间。

PHP7的性能革新

PHP长期以来饱受批评的性能问题,将会在这个版本获得大幅度的改善。版本中间没有PHP6哈,听说,是由于这个版本曾经立过项目,后来大部分功能都在5.x的版本里实现了,为了不混淆,下一个大版本直接就是PHP7。(几年之前,我还看到过关于PHP6的书籍。)

1. PHP7的介绍

虽然PHP7的正式版本可能要到2015年的10月份才发布,不过明年6月份应能够看见一个测试版本了,以后是3-4个月的质量保证。

PHP社区的项目计划以下:

 

由于项目仍然处于开发中的缘由,从表格中,能够看见的特性描述都比较模糊。确定有更多的其余特性,只是还没有公布。下面的这些,是从PHP社区看见的,由于PHP7是一个开发中的项目,下面的这些也不必定准确,不过,不妨碍咱们一块儿来看看。


  1. PHPNG(PHP next generation,下一代PHP),对Zend执行引擎自己的各类性能优化,其中JIT,可能会实如今Zend Opcache组件中。

  2. AST(Abstract Syntax Tree,抽象语法树),目的是在PHP编译过程引入一个中间件,替代直接从解释器吐出opcode的方式。让解释器和编译器解耦,能够减小大量Hack代码,同时,让实现更容易理解和维护。

  3. uniform variable syntax(统一变量语法),引入一种内部一致和完整的变量语法,让PHP的解析器更完整地支持各类类型的变量。部分变量的用法须要调整,例如变量的变量$$a等。

  4. 支持integer semantics(整型语义),例如NaN、Infinity、<<、>>,修正list()的一致性等等。


上面的特性中,最使人期待的就是PHPng的性能优化,PHP社区已经放出了一些性能的测速数据。从数据上看,PHPng的执行性能比起项目启动之初,已经有接近1倍的提高。这个成绩已经很是不错,何况,最关键的是PHP7的优化计划还有不少还没有完成。等到都所有完成了,相信咱们能够看见一个性能更高的PHP7。

这测速数据是来自于PHP社区(wiki.php.net/phpng),截取了一部分的数据:

 

对其当前PHP5.6版本,PHPNG的10月份性能提高已经很是明显了: 

 

简单翻译下:


  • 综合测试速度提高35%。

  • 在实际应用场景有20%-70%的速度提高(WordPress首页有60%的提高)

  • 更少的内存消耗

  • 支持大部分经常使用的SAPIs

  • 支持大部分的PHP拓展绑定到资源分配(69个完成,6个待迁移)

  • 提供堪比HHVM3.3.0的执行速度


2. PHP的弱类型争议

PHP被争议的特色不少,可是随着语言版本的发布和完善,功能和特性方面的批评开始变少了。可是,PHP的“弱类型”特性,却明显受到更多的争议,从HHVM经过Hack的方式直接“去掉”了“弱类型”特性能够看出,HHVM并不喜欢“弱类型”特性。然而,在咱们不少PHP程序员的眼中,这倒是PHP的重要优势之一。PHP里的变量被设计得随性和飘逸,海纳百川,一切皆可包容,不是让语言显得更为简单吗?

实际上,有些人认为它是个严重的问题,对于“弱类型”的批评观点大体以下:


  1. 在“严谨”的语言中,一般是预先定义好一个变量的类型,自始至终,变量的类型是固定的,使用范围也是固定。而PHP的变量,一般咱们只能看见它名字,类型大部分都不能够预先定义,而且还能够随意改变。(内存分配很差管理)

  2. 为了兼容弱类型特性,PHP须要实现大量兼容代码,包括类型判断、类型转换、存储方式等,增长了语言内部的复杂度。(执行效率低下)

  3. 变量的类型是不可控的,在执行过程当中存在大量的“隐性类型转换”,容易产生不可预知的结果。(这里的确须要强调,PHP的类型转换是个必须掌握的点,各类类型的互相转换的可能会产生不少问题,尤为是初学PHP的同窗哈)


他们认为,这些都不符合“所见即所得”的简单性,而语法严谨的语言更高效率,也更容易“理解”。

受到相似批评的还有Javascript等语言,由于它在这个问题上的表现是同样的。可是,一门语言最终被大规模使用,必然有它们的道理。PHP成为Web服务开发的首选脚本语言,Javascript则直接称霸Web前端领域,能走到这一步都不多是偶然因素,开发者们用脚投票选择了它们。编程语言是人类和机器沟通的桥梁,终极追求是实现“人人皆可编程”的宏伟目标。

纵观语言发展历史,从0和1的机器码开始,到汇编语言,而后到C语言,再到动态脚本语言PHP。执行效率呈指数降低,可是,学习门槛也呈指数下降。PHP语言不只屏蔽了C的内存管理和指针的复杂性,并且更进一步屏蔽了变量类型的复杂性。提高了项目开发的效率,下降了学习的门槛,但同时牺牲了必定的执行性能。而后,HHVM的Hack给咱们一种“回归原始”的感受,从新引入了变量的复杂性。固然,不一样的语言解决不一样场景下的问题,并不可以一律而论。

 

小结

HHVM对PHP的性能提高,让人眼前一亮,而磨刀霍霍的PHP7则让人万分期待。二者都是极其优秀的开源项目,都在不断前进和发展中。就目前而言,由于距离PHP7正式版的发布还有比较长的一段时间,因此当前性能优化方案的首选固然是HHVM。不过,就我我的而言,我比较看好PHP7,由于它更能作到PHP代码的向下兼容。若是二者性能相差不大,我会选择简单的那个。

相关文章
相关标签/搜索