Home >Backend Development >PHP Tutorial >【天赢金创】PHP7与Swoole

【天赢金创】PHP7与Swoole

WBOY
WBOYOriginal
2016-06-20 12:48:051018browse

原文:http://rango.swoole.com/archives/440
最近PHP官方终于发布了传说中的PHP7,虽然只是alpha版。PHP7号称是新一代的PHP,官方开发组对Zend引擎底层做了大量修改来优化PHP的性能。可以说PHP7这个版本的主题就是性能优化。

在过去PHP一直以开发效率快著称,而语言本身的性能较差(当然比Python,Ruby还是要快一些的)。普通的Web网站都是IO密集型的程序,瓶颈在MySQL上,所以体现不出PHP的性能劣势。但在密集计算方面比C/C++、Java等静态编译语言差几十倍甚至上百倍。另外使用设计非常复杂的开发框架,如Symfony、Laravel等,程序性能也会明显下降。

现在随着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势必会更加流行。

本文简单介绍一下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数组的性能一致。

从实际项目进行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("

    Hello Swoole. #".rand(1000, 9999)."


    ");
    });

    $http->start();
    PHP的未来
    可以预见PHP语言未来会在性能方面有明显的提升,越来越接近C/C++、Java等静态编译语言。再加上Swoole扩展,PHP的使用范围可以扩展到移动通信、云计算、网络游戏、物联网、车联网、智能家居等领域。

    PHP虽然未必是最好的编程语言,但PHP在向着这个方向在发展。

    Statement:
    The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn