图片 5

VM)是Fackbook推出用于在执行PHP代码的虚拟机,HHVM 是 Facebook 开发的高性能 PHP

背景

HHVM 是 Facebook 开发的高性能 PHP
虚拟机,宣称比官方的快9倍,我很好奇,于是抽空简单了解了一下,并整理出这篇文章,希望能回答清楚两方面的问题:

  • HHVM 到底靠谱么?是否可以用到产品中?
  • 它为什么比官方的 PHP 快很多?到底是如何优化的?

HHVM

HHVM是什么?

HHVM(HipHop
VM)是Fackbook推出用于在执行PHP代码的虚拟机,是一个PHP的JIT编译器,具有产生快速代码和及时编译的优点。

HHVM能干什么?

HHVM脚本主要应用服务器端脚本和命令行脚本两大领域,专注于服务器端脚本,如收集表单数据、生成动态页面、发送接受COOKIE等。

HHVM为什么比ZendEngine快?

HHVM是Facebook开发的高性能PHP虚拟机,宣称比官方Zend快9倍。

PHP使用的Zend虚拟机(VM),首先会先将PHP代码编译成二进制指令opcode,然后逐条执行,每条opcode指令都对应一个C函数。对于PHP的用户函数、运行时局部变量、常量会存在一个Hashtable中。

执行一次C函数的开销

  • 参数的入栈出栈
  • CPU寄存器状态保存

例如:在PHP中执行1000w次累加

<?php
$sum = 0;
// 发生1000w次C函数调用
for($i=0; $i<10000000; $i++){
  $sum += $i;
}

若编译为机器码情况是什么样的呢?

主频2.0GHZ的CPU每秒执行20亿次指令,函数调用则1秒只能运行1000W次。

因此,编译为机器码执行语言如C、C++、Golang…,或拥有JIT的语言如Java、NodeJS、LuaJIT、HHVM…,单从指令执行角度上看至少比PHP快几十倍。

对于字符串处理、JSON编码解码、iconv编码解码、数组操作等,
PHP比C++、Java慢吗?

在PHP中此类操作都是C扩展函数完成的,性能与编译型语言一致。

PHP到底比编译型语言慢的原因在哪里呢?

PHP代码中用户函数、类、对象操作等。

运算密集型 vs IO密集型

运算密集型程序指的是需大量执行内存复制操作、循环、运行指令等,瓶颈在CPU上,提升性能的解决方案就是提升CPU硬件配置、改进算法、提升语言/工具的执行性能。对于此类程序,PHP性能问题很明显,执行相同的逻辑,比C/C++慢几十倍甚至百倍,这是不可接受的。

IO密集型程序瓶颈在IO等待,例如HTTP请求执行100ms后返回,其中90ms查询数据库,8ms读写文件,
那么无论C/C++还是PHP,请求响应时间总是100ms左右,语言性能优化只有2ms的空间。

如何优化PHP呢

  • PHP语言层面优化
  • 优化PHP官方实现ZendEngine
  • 将PHP编译为其他语言字节码(bytecode),借助于其他语言虚拟机来运行。
  • 将PHP转成C/C++,编译成本地代码。
  • 开发更快的PHP虚拟机

Zend的执行过程可分为两个环节

  • 将PHP编译为opcode
  • 执行opcode

优化opcode可编码重复解析PHP与静态编译优化,由于PHP的动态性,这种优化方式是有局限,乐观估计可提升20%的性能。

优化opcode架构本身,工作量大投入产生比不高。

优化opcode执行,Zend解释器interpreter在读到opcode后会根据不同opcode调用不同函数(switch),在函数中执行语言相关的操作。优化空间不大。

优化Zend执行性能,对于函数调用的开销,通过inline
threading来优化,其原理如C中的inline关键字。

更快的虚拟机

HHVM 为什么更快,原因是JIT。

JIT操作本身是耗时的,对于简单程序或许比interpreter慢。HHVM的发展就是不断优化、优化、在优化。

图片 1

HHVM是如何超过HPHPc

什么是JIT,如何实现一个JIT?

动态语言中基本都会有一个eval(),作用是传入一段字符串来执行。JIT做着类似的事,不过它要拼接的不是字符串,而是不同平台下的机器码,然后执行。在JIT中更重要的优化是根据类型来生成特定的指令,从而减少指令数量和条件判断。

类型推导

JIT的关键是猜测类型,变量的类型要是老是变就很难优化。HHVM工程师考虑在PHP语法上做手脚,加上类型的支持,推出Hack。

<?hh
class Point
{
  // 使用静态类型可让HHVM更好的优化性能,不过这也意味着和PHP语法不兼容。
  public float $x,$y;
  public function __construct(float $x, float $y)
  {
    $this->x = $x;
    $this->y = $y;
  }
}

HHVM提升PHP执行性能

HHVM生成和执行PHP的在中间字节码,执行时通过JIT(Just In
Time即时编译,软件优化技术,指在运行时才会去编译字节码为机器码)转换为机器码执行。JIT将大量重复执行的字节码在运行时编译为机器码,达到提高执行效率的目的。通常触发JIT的条件是代码或函数被多次重复调用。

什么是字节码?

图片 2

字节码

ZendEngine做法是先编译为opcode,逐条执行,每条指令对应的是C语言级别的函数。

HHVM服务器最开始的少数请求会比其余的慢,因为它必须在执行PHP和Hack代码之前将它们编译成机器码,这个效果是非常明显的,所以你不应当立即把一个新设置的HHVM服务器应用到生产环境中。你应该先发送一些人工模拟的请求到这个HHVM服务器上,对它进行热身。
事实上,服务器启动的时候,并不会编译任何代码。初始的请求就是在HHVM的字节码解释器下运行的。原理就是:对于一个web服务器来说,最初的几个请求是不寻常的。在这个期间,开始了初始化,还对缓存进行填充等等。对这些代码路径的编译对整体性能的表现是非常糟糕的,因为一旦对服务器进行了预热,这些过程是不会被经常调用的。HHVM还利用这些请求,来收集一些代码所用到的数据类型分析的工作。所以它可以稍后更加有效地进行编译。你可以使用选项
hhvm.jit_profile_interp_requests 来调整这个门槛。
对于发送预热请求,颗通过命令行或其它类似的地方,简单地使用 curl
这个命令功能。为了得到最好的结果:
使用你希望在产品中看到的,能够代表最常见的请求的混合集合。例如,如果你期待所有对这个产品的请求中的40%都是到达
index.php 的,那么你的 40% 的预热请求都 应该是到 index.php 的请求。
避免并行发送多个预热请求,若你真的并行发送了多个请求,那么并不会出现什么问题。单对于JIT编译器来说,若没有同时工作在多个请求上的话,它往往能够生成更好的代码。
最终,你最好有个进程脚本用于服务器热身,这样的话,颗在命令行里仅仅执行一个命令就可以做到热身了。但是在最初期的时候,你还需要一些人工的参与,要实际计算出用于热身的请求数量是非常微妙的,
这主要取决于你的程序本身。

图片 3

你会怎么做?

在讨论 HHVM 实现原理前,我们先设身处地想想:假设你有个 PHP
写的网站遇到了性能问题,经分析后发现很大一部分资源就耗在 PHP
上,这时你会怎么优化 PHP 性能?

比如可以有以下几种方式:

  • 方案1,迁移到性能更好的语言上,如 Java、C++、Go。
  • 方案2,通过 RPC 将功能分离出来用其它语言实现,让 PHP
    做更少的事情,比如 Twitter 就将大量业务逻辑放到了 Scala 中,前端的
    Rails 只负责展现。
  • 方案3,写 PHP 扩展,在性能瓶颈地方换 C/C++。
  • 方案4,优化 PHP 的性能。

方案1几乎不可行,十年前 Joel 就拿 Netscape
的例子警告过,你将放弃多年的经验积累。尤其是像
Facebook 这种业务逻辑复杂的产品,PHP
代码实在太多了,据称有2千万行(引用自 [PHP on the Metal with
HHVM]),修改起来的成本恐怕比写个虚拟机还大,而且对于一个上千人的团队,从头开始学习也是不可接受的。

方案2是最保险的方案,可以逐步迁移,事实上 Facebook
也在朝这方面努力了,而且还开发了 Thrift 这样的 RPC 解决方案。Facebook
内部主要使用的另一个语言是 C++,从早期的 Thrift
代码就能看出来,因为其它语言的实现都很简陋,没法在生产环境下使用。

目前在 Facebook 中据称 PHP:C++ 已经从 9:1 增加到 7:3
了,加上有
Andrei Alexandrescu 的存在,C++ 在 Facebook
中越来越流行。但这只能解决部分问题,毕竟 C++ 开发成本比 PHP
高得多,不适合用在经常修改的地方,而且太多 RPC 的调用也会严重影响性能。

方案3看起来美好,实际执行起来却很难,一般来说性能瓶颈并不会很显著,大多是不断累加的结果,加上
PHP
扩展开发成本高,这种方案一般只用在公共且变化不大的基础库上,所以这种方案解决不了多少问题。

可以看到,前面3个方案并不能很好地解决问题,所以 Facebook
其实没有选择的余地,只能去考虑 PHP 本身的优化了。

摘要:近日,PHP7和HHVM的性能之争成为了一个讨论热点,但毫无疑问,它们都在提升PHP执行性能方面取得了突破性的进展。本期《问底》,徐汉彬将为大家科普和介绍它们的性能之争。徐汉彬曾在阿里巴巴和腾讯从事4年多的技术研发工作,负责过日请求量过亿的Web系统升级与重构,目前在小满科技创业,从事SaaS服务技术建设。最近,PHP7和HHVM的性能之争成为了一个讨论热点,它们都在提升PHP执行性能方面取得了突破性的进展。这篇文章,参考了两个社区的技术新进展,为大家科普和介绍它们的性能之争。
PHP语言的排名变化根据“TIOBE编程语言排行榜”,2010年PHP最高曾经在世界编程语言中排名第三。可见,PHP语言在PC互联网时代的Web领域可谓叱咤风云,擎天一柱。
在PHP程序员中,曾经流传着一个段子:引用某女:你能让这个论坛的人都吵起来,我就跟你吃饭。
PHP程序员:PHP是世界上最好的语言! 某论坛炸锅了,各种吵架……
某女:服了你了,我们走吧!
PHP程序员:今天不行,我一定要说服他们,PHP必须是最好的语言。好了,我们言归正传,语言本身无分好坏,只是在各自使用的场景中解决不同的问题。互联网的时代车轮是很快的,随着移动互联网的到来,在短短四年多的时间里,移动端技术发展横扫全球。与此同时,各种语言群雄并起,而昔日辉煌的PHP从原来的编程语言的榜单看,下降到第六位。于是,唱衰PHP的声音此起彼伏。但是,鸟哥在2014年的Qcon分享中有一个数据,全球排名前100万的网站中,81.3%使用的Web服务端脚本语言是PHP,2013年同期是78.3%。也就是说,PHP的在Web服务方面并没有减少,只是在移动互联网浪潮中,增加了很多的其他语言技术的应用,进而被稀释了。最近关于PHP7和HHVM的性能对比,成为了一个热点的争议话题,大家都在讨论和关注哪一个才是PHP性能提升的未来。HHVM的起源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 =

更快的 PHP

既然要优化 PHP,那如何去优化呢?在我看来可以有以下几种方法:

  • 方案1,PHP 语言层面的优化。
  • 方案2,优化 PHP 的官方实现(也就是 Zend)。
  • 方案3,将 PHP 编译成其它语言的
    bytecode(字节码),借助其它语言的虚拟机(如 JVM)来运行。
  • 方案4,将 PHP 转成 C/C++,然后编译成本地代码。
  • 方案5,开发更快的 PHP 虚拟机。

PHP 语言层面的优化是最简单可行的,Facebook
当然想到了,而且还开发了 XHProf 这样的性能分析工具,对于定位性能瓶颈是很有帮助的。

不过 XHProf 还是没能很好解决 Facebook
的问题,所以我们继续看,接下来是方案2。简单来看,Zend
的执行过程可以分为两部分:将 PHP 编译为 opcode、执行 opcode,所以优化
Zend 可以从这两方面来考虑。

优化 opcode 是一种常见的做法,可以避免重复解析
PHP,而且还能做一些静态的编译优化,比如 Zend Optimizer
Plus,但由于 PHP
语言的动态性,这种优化方法是有局限性的,乐观估计也只能提升20%的性能。另一种考虑是优化
opcode
架构本身,如基于寄存器的方式,但这种做法修改起来工作量太大,性能提升也不会特别明显(可能30%?),所以投入产出比不高。

另一个方法是优化 opcode 的执行,首先简单提一下 Zend 是如何执行的,Zend
的 interpreter(也叫解释器)在读到 opcode 后,会根据不同的 opcode
调用不同函数(其实有些是
switch,不过为了描述方便我简化了),然后在这个函数中执行各种语言相关的操作(感兴趣的话可看看深入理解
PHP
内核这本书),所以
Zend 中并没有什么复杂封装和间接调用,作为一个解释器来说已经做得很好了。

想要提升 Zend
的执行性能,就需要对程序的底层执行有所解,比如函数调用其实是有开销的,所以能通过 Inline
threading 来优化掉。它的原理就像
C 语言中的 inline
关键字那样,但它是在运行时将相关的函数展开,然后依次执行(只是打个比方,实际实现不太一样),同时还避免了
CPU 流水线预测失败导致的浪费。

另外还可以像 JavaScriptCore 和 LuaJIT 那样使用汇编来实现
interpreter,具体细节建议看看 Mike
的解释。

但这两种做法修改代价太大,甚至比重写一个还难,尤其是要保证向下兼容,后面提到
PHP 的特点时你就知道了。

开发一个高性能的虚拟机不是件简单的事情,JVM
花了10多年才达到现在的性能,那是否能直接利用这些高性能的虚拟机来优化 PHP
的性能呢?这就是方案3的思路。

其实这种方案早就有人尝试过了,比如 Quercus 和
IBM 的 P8,Quercus 几乎没见有人使用,而
P8 也已经死掉了。Facebook
也曾经调研过这种方式,甚至还出现过不靠谱的传闻 ,但其实
Facebook 在 2011 年就放弃了。

因为方案3看起来美好,但实际效果却不理想,按照很多大牛的说法(比如 Mike),VM
总是为某个语言优化的,其它语言在上面实现会遇到很多瓶颈,比如动态的方法调用。关于这点在 Dart
的文档中有过介绍,而且据说
Quercus 的性能与 Zend+APC 比差不了太多([来自The HipHop Compiler for
PHP]),所以没太大意义。

不过 OpenJDK
这几年也在努力,最近的 Grall 项目看起来还不错,也有语言在上面取得了显著的效果,但我还没空研究
Grall,所以这里无法判断。

接下来是方案4,它正是 HPHPc(HHVM 的前身)的做法,原理是将 PHP 代码转成
C++,然后编译为本地文件,可以认为是一种 AOT(ahead of
time)的方式,关于其中代码转换的技术细节可以参考 The HipHop Compiler
for
PHP 这篇论文,以下是该论文中的一个截图,可以通过它来大概了解:

图片 4

这种做法的最大优点是实现简单(相对于一个 VM
来说),而且能做很多编译优化(因为是离线的,慢点也没事),比如上面的例子就将“- 1”优化掉了。但它很难支持
PHP
中的很多动态的方法,如 eval()create_function(),因为这就得再内嵌一个
interpreter,成本不小,所以 HPHPc 干脆就直接不支持这些语法。

除了
HPHPc,还有两个类似的项目,一个是 Roadsend,另一个是 phc ,phc
的做法是将 PHP 转成了 C 再编译,以下是它将 file_get_contents($f) 转成
C 代码的例子:

static php_fcall_info fgc_info;
php_fcall_info_init ("file_get_contents", &fgc_info);
php_hash_find (LOCAL_ST, "f", 5863275, &fgc_info.params);
php_call_function (&fgc_info);

话说 phc
作者曾经在博客上哭诉,说他两年前就去
Facebook 演示过 phc
了,还和那里的工程师交流过,结果人家一发布就火了,而自己忙活了4年却默默无闻,现在前途渺茫。。。

Roadsend 也已经不维护了,对于 PHP
这样的动态语言来说,这种做法有很多的局限性,由于无法动态
include,Facebook 将所有文件都编译到了一起,上线时的文件部署居然达到了
1G,越来越不可接受了。

另外有还有一个叫 PHP
QB 的项目,由于时间关系我没有看,感觉可能是类似的东东。

所以就只剩下一条路了,那就是写一个更快的 PHP
虚拟机,将一条黑路走到底。或许你和我一样,一开始听到 Facebook
要做一个虚拟机是觉得太离谱,但如果仔细分析就会发现其实也只有这样了。

200;//通常是4字节但是,如果是PHP定义了一个同样的变量,实际对应的存储结构则是:这个结构体将会占据远比C变量多得多的内存,PHP中定义方式如下:$a

200;//这变量将实际占用对比C变量很多倍的存储空间。其实对PHP来说,无论存储什么类型的数据,都是用上述“通杀”的结构体实现。为了兼容PHP程序员的变量类型“乱入”,PHP做到了对开发者的友好,但是对执行引擎很残酷。单个变量内存消耗可能还不明显,一旦用到PHP的数组等,则复杂度指数上升。然后,Zend引擎执行时,将这些PHP代码编译为opcode,由Zend引擎逐行解释执行。无论是字符串的连接操作,还是数组的简单修改等,几乎都是“PHP程序员一句话,Zend引擎跑断腿”的节奏。因此,同样的操作,对比C来说,PHP消耗了更多的CPU和内存等系统资源。除此之外,还有内存自动回收、变量类型判断等等,都会增加系统资源的消耗。例如,我用纯PHP实现的快速排序函数和原生sort函数,排序10000个整型数字,来做一个耗时对比,结果如下:原生的sort耗时3.44
ms,而我们自己实现的PHP函数sort则是68.79
ms。我们发现,两者执行效率差距巨大。我的测试方式,是计算函数执行前后的时间间隔,而不是整个PHP脚本从启动到结束的时间。PHP脚本启动和关闭过程,本身有着一系列的初始化和清理工作,也会占据不少的耗时。
通常情况下,PHP执行效率的排行是:最快的是PHP语言结构,PHP语言的一部分。然后比较快的就是PHP的原生和拓展函数。PHP拓展,基于Zend
API之上,用C实现的功能,执行效率和C++/Java是属于同一个数量级的。真正慢的就是,我们通过PHP自己写的代码和函数。例如,假如我们使用的比较重的纯PHP实现的框架,因为框架本身的模块很多,所以,会明显拖累语言层面的执行效率,同时占据更多的内存。在一般情况下,我们并不推荐用过PHP实现逻辑复杂计算类型的功能,尤其是Web系统流量比较大的场景下。因此,PHP程序员应该对PHP的各种原生函数和各类拓展有一个比较广泛的了解,在具体的功能实现场景中,寻求更原生的解决方案,而不是自己写一堆复杂的PHP代码来实现这类型功能。如果有足够的PHP拓展开发实力,将这类型业务功能重写为一个PHP拓展,也会大幅提升代码的执行效率。这是一个非常不错的方式,也被广泛应用PHP优化中。但是,自己编写的PHP业务拓展的缺点也很明显:拓展开发耗时比较长,需求变更的时候修改也复杂,写得不好可能会影响Web服务稳定性。拓展在PHP版本升级的时候,可能需要做额外的兼容工作。人员变动后的维护和接手成本也比较高。实际上,在互联网一线企业中,更常见的解决方案,并非增加PHP拓展,而用C/C++独立写一个服务server,然后PHP通过socket和服务server通信来完成业务处理,并不将PHP本身和业务耦合在一起。不过,Web服务大部分的性能瓶颈都在网络传输和其他服务server的耗时上,PHP执行的耗时在整体耗时的占用比例非常小,所以从业务角度来说,影响可能并不明显。2.
HHVM提升PHP执行性能的方式
HHVM提升PHP性能的途径,采用的方式就是替代Zend引擎来生成和执行PHP的中间字节码,执行时通过JIT转为机器码执行。Zend引擎默认做法,是先编译为opcode,然后再逐条执行,通常每条指令对应的是C语言级别的函数。如果我们产生大量重复的opcode,对应的则是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的部署和应用都存在一些的问题:服务部署比较复杂,有一定维护成本。对PHP原生代码并非完整支持,PHP拓展也需要做适当的兼容。HHVM是个新虚拟机,长时间运行有内存泄露。HHVM毕竟是一个相对比较新的开源项目,发展到成熟仍然需要一定时间。PHP7的性能革新PHP长期以来饱受批评的性能问题,将会在这个版本得到大幅度的改善。版本中间没有PHP6哈,据说,是因为这个版本曾经立过项目,后来大部分功能都在5.x的版本里实现了,为了避免混淆,下一个大版本直接就是PHP7。1.
PHP7的介绍
虽然PHP7的正式版本可能要到2015年的10月份才发布,不过明年6月份应可以看见一个测试版本了,之后是3-4个月的质量保证。PHP社区的项目计划如下:因为项目仍然处于开发中的原因,从表格中,可以看见的特性描述都比较模糊。肯定有更多的其他特性,只是尚未公布。下面的这些,是从PHP社区看见的,因为PHP7是一个开发中的项目,下面的这些也不一定准确,不过,不妨碍我们一起来看看。PHPNG,对Zend执行引擎本身的各种性能优化,其中JIT,可能会实现在Zend
Opcache组件中。AST,目的是在PHP编译过程引入一个中间件,替代直接从解释器吐出opcode的方式。让解释器和编译器解耦,可以减少大量Hack代码,同时,让实现更容易理解和维护。uniform
variable
syntax,引入一种内部一致和完整的变量语法,让PHP的解析器更完整地支持各种类型的变量。部分变量的用法需要调整,例如变量的变量$$a等。支持integer
semantics,例如NaN、Infinity、、,修正list()的一致性等等。上面的特性中,最令人期待的就是PHPng的性能优化,PHP社区已经放出了一些性能的测速数据。从数据上看,PHPng的执行性能比起项目启动之初,已经有接近1倍的提升。这个成绩已经非常不错,况且,最关键的是PHP7的优化计划还有很多尚未完成。等到都全部完成了,相信我们可以看见一个性能更高的PHP7。这测速数据是来自于PHP社区,截取了一部分的数据:对其当前PHP5.6版本,PHPNG的10月份性能提升已经非常明显了:
简单翻译下:综合测试速度提升35%。在实际应用场景有20%-70%的速度提升更少的内存消耗支持大部分常用的SAPIs支持大部分的PHP拓展绑定到资源分配提供堪比HHVM3.3.0的执行速度2.
PHP的弱类型争议
PHP被争议的特点很多,但是随着语言版本的发布和完善,功能和特性方面的批评开始变少了。但是,PHP的“弱类型”特性,却明显受到更多的争议,从HHVM通过Hack的方式直接“去掉”了“弱类型”特性可以看出,HHVM并不喜欢“弱类型”特性。然而,在我们很多PHP程序员的眼中,这却是PHP的重要优点之一。PHP里的变量被设计得随性和飘逸,海纳百川,一切皆可包容,不是让语言显得更为简单吗?实际上,有些人认为它是个严重的问题,对于“弱类型”的批评观点大致如下:在“严谨”的语言中,通常是预先定义好一个变量的类型,自始至终,变量的类型是固定的,使用范围也是固定。而PHP的变量,通常我们只能看见它名字,类型大部分都不可以预先定义,并且还可以随意改变。为了兼容弱类型特性,PHP需要实现大量兼容代码,包括类型判断、类型转换、存储方式等,增加了语言内部的复杂度。变量的类型是不可控的,在执行过程中存在大量的“隐性类型转换”,容易产生不可预知的结果。他们认为,这些都不符合“所见即所得”的简单性,而语法严谨的语言更高效率,也更容易“理解”。受到类似批评的还有Javascript等语言,因为它在这个问题上的表现是一样的。但是,一门语言最终被大规模使用,必然有它们的道理。PHP成为Web服务开发的首选脚本语言,Javascript则直接称霸Web前端领域,能走到这一步都不可能是偶然因素,开发者们用脚投票选择了它们。编程语言是人类和机器沟通的桥梁,终极追求是实现“人人皆可编程”的宏伟目标。纵观语言发展历史,从0和1的机器码开始,到汇编语言,然后到C语言,再到动态脚本语言PHP。执行效率呈指数下降,但是,学习门槛也呈指数降低。PHP语言不仅屏蔽了C的内存管理和指针的复杂性,而且更进一步屏蔽了变量类型的复杂性。提升了项目开发的效率,降低了学习的门槛,但同时牺牲了一定的执行性能。然后,HHVM的Hack给我们一种“回归原始”的感觉,重新引入了变量的复杂性。当然,不同的语言解决不同场景下的问题,并不能够一概而论。小结HHVM对PHP的性能提升,让人眼前一亮,而磨刀霍霍的PHP7则让人万分期待。两者都是极其优秀的开源项目,都在不断前进和发展中。就目前而言,因为距离PHP7正式版的发布还有比较长的一段时间,所以当前性能优化方案的首选当然是HHVM。不过,就我个人而言,我比较看好PHP7,因为它更能做到PHP代码的向下兼容。如果两者性能相差不大,我会选择简单的那个。

更快的虚拟机

HHVM 为什么更快?在各种新闻报道中都提到了 JIT
这个关键技术,但其实远没有那么简单,JIT
不是什么神奇的魔法棒——用它轻轻一挥就能提升性能,而且 JIT
这个操作本身也是会耗时的,对于简单的程序没准还比 interpreter
慢,最极端的例子是 LuaJIT
2 的
Interpreter 就稍微比 V8 的 JIT
快。所以并不存在绝对的事情,更多还是在细节问题的处理上,HHVM
的发展历史就是不断优化的历史,你可以从下图看到它是如何一点点超过 HPHPc
的:

图片 5

值得一提的是在 Android 4.4 中新的虚拟机 ART 就采用的是 AOT
方案(还记得么?前面提到的 HPHPc 就是这种),结果比之前使用 JIT 的
Dalvik 快了一倍,所以说 JIT 也不一定比 AOT 快。

因此这个项目是有很大风险的,如果没有强大的内心和毅力,极有可能半途而废。Google
就曾经想用 JIT 提升 Python
的性能,但最终失败了,对于
Google 来说用到 Python 的地方其实并没什么性能问题(好吧,以前 Google
是用 Python 写过 crawl [参考 In The Plex],但那都是1996年的事情了)。

比起 Google,Facebook 显然有更大的动力和决心,PHP 是 Facebook
最重要的语言,我们来看看 Facebook 都投入了哪些大牛到这个项目中(不全):

  • Andrei Alexandrescu,『Modern C++ Design』和『C++ Coding
    Standards』的作者,C++ 领域无可争议的大神
  • Keith Adams,负责过 VMware 核心架构,当年 VMware 就派他一人去和
    Intel
    进行技术合作,足以证明在 VMM 领域他有多了解了
  • Drew Paroski,在微软参与过 .NET 虚拟机开发,改进了其中的 JIT。
  • Jason Evans,开发了 jemalloc,减少了 Firefox 一半的内存消耗。
  • Sara Golemon,『Extending and Embedding PHP』的作者,PHP
    内核专家,这本书估计所有 PHP 高手都看过吧,或许你不知道其实她是女的

虽然没有像 Lars Bak、Mike Pall
这样在虚拟机领域的顶级专家,但如果这些大牛能齐心协力,写个虚拟机还是问题不大的,那么他们将面临什么样的挑战呢?接下来我们一一讨论。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章