原文:http://rango.swoole.com/archives/440
最近PHP官方终于发布了传说中的PHP7,虽然只是alpha版。PHP7号称是新一代的PHP,官方开发组对Zend引擎底层作了大量修改来优化PHP的性能。能够说PHP7这个版本的主题就是性能优化。php
在过去PHP一直以开发效率快著称,而语言自己的性能较差(固然比Python,Ruby仍是要快一些的)。普通的Web网站都是IO密集型的程序,瓶颈在MySQL上,因此体现不出PHP的性能劣势。但在密集计算方面比C/C++、Java等静态编译语言差几十倍甚至上百倍。另外使用设计很是复杂的开发框架,如Symfony、Laravel等,程序性能也会明显降低。html
如今随着PHP愈来愈流行,像Facebook、新浪微博这样超大型规模的网站都在使用PHP。PHP语言性能问题就愈来愈严重了。Facebook有几十万台服务器,若是现有的PHP程序能够提高一部分性能,将会节约大量的服务器资源。因此就有了HHVM、Hack。Hack为PHP增长了类型,HHVM是一个从新设计的PHP引擎,实际项目中使用HHVM能够提近70%的性能。实际项目70%性能提高这是一个什么概念?腾讯QQ农场最初使用PHP开发,后由于性能问题使用C语言重构,完成后性能提高了100%。程序员
PHP官方也注意到了这个问题,因此就有了PHP7的开发计划。最新公布的PHP7-alpha在WordPress项目中测试的表现已经超越了HHVM。将来PHP将会同时具有极高的开发效率和极高的性能,再结合Swoole作异步编程,PHP势必会更加流行。web
本文简单介绍一下PHP7作了哪些优化,能够提高如此多性能。算法
一 zval使用栈内存
在Zend引擎和扩展中,常常要建立一个PHP的变量,底层就是一个zval指针。以前的版本都是经过MAKE_STD_ZVAL动态的从堆上分配一个zval内存。而PHP7能够直接使用栈内存。PHP代码中建立的变量也进行了优化,PHP7直接在栈内存上预分配zval。这样节约了大量内存分配和内存管理的操做。编程
PHP5数组
zval *val; MAKE_STD_ZVAL(val);
PHP7性能优化
zval val;
二 zend_string存储hash值,array查询再也不须要重复计算hash
PHP7为字符串单首创建了新类型叫作zend_string,除了char *指针和长度以外,增长了一个hash字段,用于保存字符串的hash值。PHP中array是核心数据结构,PHP程序中每每都有大量的$array[$key]操做,虽然hashtable查找的时间复杂度是O(1),但$key要转为hash值是要通过计算的。不只仅是array操做,实际上PHP底层对于类属性、类方法、函数,访问时都要先经过hashtable查找到对应的指针,再执行对应的操做。PHP7以前Zend引擎会有大量的CPU时间用于计算hash值。服务器
实际上PHP程序运行起来以后,大部分状况下$key的值都是不变的。PHP7干脆将这个hash值保存起来,下次直接使用,这样就节省了大量的hash计算操做,PHP的hashtable与C数组的性能一致。websocket
从实际项目进行callgrind性能分析,会发现alloc和hash 2项操做就占用了至关大比例的CPU时间。PHP7优化以后这2项操做占用的CPU时间下降了很是多。(注:zend_hash仍然占12%,由于总体CPU下降了,因此总的耗时下降了很多)
三 hashtable桶内直接存数据
PHP5的hashtable每一个元素都是一个 Bucket *,而PHP7直接存Bucket,减小了内存申请次数,提高了Cache命中率和内存访问速度。
四 zend_parse_parameters改成宏实现
PHP的C扩展函数与PHP中的变量进行参数输入时,要使用zend_parse_parameters()函数,这个函数根据一个字符串参数找到对应PHP的zval指针,而后进行赋值。 这个函数实际上有必定的性能消耗。PHP7直接使用宏替换了zend_parse_parameters函数,C扩展中再也不须要使用zend_parse_parameters进行逐个参数的查找,宏展开后自动会实现参数赋值。仅此一项就提高了5%的性能。
五 新增长4种OPCODE
不少PHP程序中会大量使用call_user_function, is_int/string/array, strlen , defined 函数。PHP5 都是以扩展函数的方式提供,PHP7中这4类函数改为ZendVM的OPCODE指令,执行更快。
六 其余更多优化
除了上面5个主要优化点以外,PHP7还有其余更多的细节性能优化。如基础类型int、float、bool等改成直接进行值拷贝,排序算法改进,PCRE with JIT,execute_data和opline使用全局寄存器等等。PHP7对性能的优化会继续进行下去。
PHP7-alpha相比PHP5.6性能提高了近3倍。下面是WordPress在PHP7上的表现:
PHP7的新特性
除了性能优化外,PHP7新增长了2项重要的新特性。
变量类型
PHP7版本函数的参数和返回值增长了类型限定。为何PHP要加入类型,实际上此项特性是为了PHP7.1版本的JIT特性作准备,增长类型后PHP JIT能够准确判断变量类型,生成最佳的机器指令。
function test(int $a, string $b, array $c) : int {
//code
}
错误异常
PHP程序出错后过去Zend引擎会发生致命错误并终止程序运行,PHP7可使用try/catch捕获错误。底层使用Exeception代替了Fatal Error。这个特性表示PHP语言正在向一个更加规范的方向发展。应用层与底层在错误抛出的方式所有统一为异常。
try {
non_exists_func();
} catch (EngineException $e) {
echo "Exception: {$e->getMessage()}\n";
}
匿名类
$test = new class("Hello World") {
public function __construct($greeting) {
$this->greeting = $greeting;
}
};
PHP7与JIT
最初PHP7性能优化的方向并非以上所讲的,而是JIT。JIT是just in time的缩写,表示运行时将指令转为二进制机器码。Java语言的JVM引擎底层就是使用JIT将Java字节码编译为二进制机器码执行。PHP7开发过程当中有一个中间版本是基于JIT,后来开发组发现使用JIT后,对于实际项目并无有太大的性能提高,因此PHP7最终放弃了JIT方案,PHP7.0-final版本不会携带JIT特性。
但若是是密集计算类程序就不一样了,使用JIT将PHP OpCode编译为机器码,运算的性能会大幅提高。PHP官方开发组在2014年末重启了JIT的开发工做。
PHP的异步网络通讯扩展Swoole
PHP在大部分程序员印象中都是用来作Web网站的。PHP没有像Python的Twisted、Tornado,Java的Netty、Mina,JavaScript的Node.js等框架,没法实现异步网络通讯程序。PHP的Swoole扩展就是为了弥补此项缺陷而诞生的开源项目。Swoole是一个标准的PHP扩展,为PHP提供了一系列异步IO、事件驱动、并行数据结构功能。
Swoole与Node.js很是类似,不一样之处是Swoole在并行提供了底层支持。Node.js是一个单进程单线程的程序,在多核服务器上没法发挥所有CPU核的计算能力。须要程序员自行使用child_process/cluster扩展或者启动多实例,使程序可以利用到多核优点。而Swoole在底层就支持了多线程/多进程,程序启动后就会建立好多个IO线程和多个Worker进程。程序员仅需配置线程/进程数量便可。
使用Swoole开发的TCP服务器程序:
$serv = new swoole_server("127.0.0.1", 9501);
$serv->on('connect', function ($serv, $fd){
echo "Client:Connect.\n";
});
$serv->on('receive', function ($serv, $fd, $from_id, $data) {
$serv->send($fd, $data);
});
$serv->on('close', function ($serv, $fd) {
echo "Client: Close.\n";
});
$serv->start();
Swoole一样也内置了http_server和WebSocket服务器的支持。swoole_http_server与传统的php-fpm不一样,它是在PHP内进行事件循环的,基于swoole_http_server彻底能够开发出相似Java应用服务器同样,能够控制完整对象生命周期的程序。swoole_http_server自然支持异步IO,能够很方便的实现支持大量TCP链接的Comet服务。swoole_websocket_server能够用来实现支持Web实时推送的程序。
使用Swoole的Web服务器程序:
$http = new swoole_http_server("0.0.0.0", 9501);
$http->on('request', function ($request, $response) {
$response->header("Content-Type", "text/html; charset=utf-8");
$response->end("
<h1>Hello Swoole. #".rand(1000, 9999)."</h1>
");
});
$http->start();
PHP的将来
能够预见PHP语言将来会在性能方面有明显的提高,愈来愈接近C/C++、Java等静态编译语言。再加上Swoole扩展,PHP的使用范围能够扩展到移动通讯、云计算、网络游戏、物联网、车联网、智能家居等领域。
PHP虽然未必是最好的编程语言,但PHP在向着这个方向在发展。