歡迎您光臨本站 註冊首頁

PHP7與Swoole

←手機掃碼閱讀     admin @ 2015-09-20 , reply:0

最近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

1
zval *val; MAKE_STD_ZVAL(val);

PHP7

1
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項重要的新特性。

1. 變數類型

PHP7版本函數的參數和返回值增加了類型限定。為什麼PHP要加入類型,實際上此項特性是為了PHP7.1版本的JIT特性做準備,增加類型后PHP JIT可以準確判斷變數類型,生成最佳的機器指令。

1
2
3
function test(int $a, string $b, array $c) : int {
//code
}

2. 錯誤異常

PHP程序出錯後過去Zend引擎會發生致命錯誤並終止程序運行,PHP7可以使用try/catch捕獲錯誤。底層使用Exeception代替了Fatal Error。這個特性表示PHP語言正在向一個更加規範的方向發展。應用層與底層在錯誤拋出的方式全部統一為異常。

1
2
3
4
5
try {
non_exists_func();
} catch (EngineException $e) {
echo "Exception: {$e->getMessage()}\n";
}

3. 匿名類

1
2
3
4
5
$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伺服器程序:

1
2
3
4
5
6
7
8
9
10
11
$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伺服器程序:

1
2
3
4
5
6
7
8
$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在向著這個方向在發展。



[admin ] PHP7與Swoole已經有608次圍觀

http://coctec.com/docs/program/show-post-204824.html