原文: http://rango.swoole.com/archives/440
最近、PHP 関係者は、まだアルファ版ではありますが、ついに伝説的な PHP7 をリリースしました。 PHP7 は新世代の PHP として知られており、公式開発チームは PHP のパフォーマンスを最適化するために Zend エンジンの最下層に多くの変更を加えました。このバージョンの PHP7 のテーマはパフォーマンスの最適化であると言えます。
これまで、PHP は開発効率が速いことで知られてきましたが、言語自体のパフォーマンスは貧弱でした (もちろん Python や Ruby よりも高速です)。通常の Web サイトは IO 集中型のプログラムであり、ボトルネックは MySQL であるため、PHP のパフォーマンス上の欠点を反映できません。ただし、集中的な計算という点では、C/C++ や Java などの静的コンパイル言語よりも数十倍、さらには数百倍も劣ります。さらに、Symfony、Laravel などの非常に複雑な設計の開発フレームワークを使用すると、プログラムのパフォーマンスも大幅に低下します。
PHP の人気が高まるにつれて、Facebook や Sina Weibo などの非常に大規模な Web サイトで PHP が使用されています。 PHP 言語のパフォーマンスの問題はますます深刻になっています。 Facebook には数十万台のサーバーがあります。既存の PHP プログラムでパフォーマンスを向上させることができれば、サーバー リソースを大幅に節約できます。そこで、HHVM と Hack が登場します。 Hack は PHP に型を追加します。HHVM は再設計された PHP エンジンです。実際のプロジェクトでは、HHVM を使用するとパフォーマンスが 70% 近く向上します。実際のプロジェクトでの 70% のパフォーマンス向上の概念とは何ですか? Tencent QQ Farm は当初 PHP を使用して開発されましたが、パフォーマンスの問題のため、後に C 言語を使用してリファクタリングされ、完成後はパフォーマンスが 100% 向上しました。
PHP 関係者もこの問題に気づいており、PHP7 の開発計画を立てています。 WordPress プロジェクトで新しく発表された PHP7-alpha のパフォーマンスは HHVM を上回りました。将来的には、PHP は非常に高い開発効率と非常に高いパフォーマンスを兼ね備え、非同期プログラミングの Swoole と組み合わせることで、さらに普及することは間違いありません。
この記事では、パフォーマンスを大幅に向上させることができる PHP7 での最適化を簡単に紹介します。
1 zval はスタック メモリを使用します
Zend エンジンと拡張機能では、多くの場合、PHP 変数を作成する必要があり、最下層は zval ポインターです。以前のバージョンでは、MAKE_STD_ZVAL を使用して、ヒープから zval メモリを動的に割り当てていました。 PHP7はスタックメモリを直接利用できます。 PHP コードで作成された変数も最適化されており、PHP7 は zval をスタック メモリに直接事前に割り当てます。これにより、多くのメモリ割り当てとメモリ管理操作が節約されます。
PHP5
zval *val; MAKE_STD_ZVAL(val);
PHP7
zval val;
2 番目の zend_string にはハッシュ値が格納され、配列クエリは不要になりました。繰り返される hash
の計算 PHP7 では、文字列に対して zend_string という新しい型が作成され、char * ポインターと長さに加えて、文字列のハッシュ値を保存するためのハッシュ フィールドが追加されます。配列は PHP の中核となるデータ構造です。PHP プログラムでは多くの $array[$key] 操作が行われますが、ハッシュテーブル検索の計算量は O(1) ですが、$key をハッシュ値に変換する必要があります。計算されます。実際、PHP の下部にあるクラス属性、クラス メソッド、および関数にアクセスするときは、まずハッシュテーブルを通じて対応するポインターを見つけてから、対応する操作を実行する必要があります。 PHP7 より前は、Zend エンジンはハッシュ値の計算に多くの CPU 時間を使用していました。
実際、PHP プログラムの実行後、ほとんどの場合、$key の値は変更されません。 PHP7 はハッシュ値を保存し、次回はそれを直接使用するため、多くのハッシュ計算操作が節約され、PHP のハッシュテーブルのパフォーマンスは C 配列のパフォーマンスと一致します。
実際のプロジェクトから callgrind のパフォーマンスを分析すると、alloc と hash の 2 つの操作が CPU 時間のかなりの部分を占めていることがわかります。 PHP7 の最適化後、これら 2 つの操作に占有される CPU 時間は大幅に短縮されました。 (注: zend_hash は依然として 12% を占めます。全体の CPU が削減されたため、合計の所要時間は大幅に削減されました)
3 つのハッシュテーブル バケットにデータを直接格納
PHP5 のハッシュテーブルの各要素は 1 つの Bucket * ですが、PHP7 は Bucket を直接保存するため、メモリ アプリケーションの数が減り、キャッシュ ヒット率とメモリ アクセス速度が向上します。
4 つの zend_parse_parameters がマクロ実装に変更されました
PHP の C 拡張関数と PHP の変数の間にパラメーターを入力する場合、この関数は zend_parse_parameters() 関数を使用して、PHP に対応する zval ポインターを検索します。文字列パラメータを指定し、値を割り当てます。 この関数は実際には一定のパフォーマンス コストを伴います。 PHP7 はマクロを直接使用して zend_parse_parameters 関数を置き換えます。C 拡張機能では、パラメータの割り当てをマクロ展開後に zend_parse_parameters を使用して 1 つずつ検索する必要がなくなりました。これだけでパフォーマンスが 5% 向上します。
5 4 つの新しい OPCODE が追加されました
多くの PHP プログラムは、call_user_function、is_int/string/array、strlen、および定義された関数を広範囲に使用します。 PHP5では、PHP7のこれら4種類の関数を、より高速に実行できるZendVMのOPCODE命令に変更して提供しています。
その他 6 つの最適化
上記の 5 つの主要な最適化ポイントに加えて、PHP7 にはその他のより詳細なパフォーマンスの最適化があります。たとえば、int、float、bool などの基本型が値を直接コピーするように変更され、ソート アルゴリズムが改善され、JIT を使用した PCRE、execute_data および opline がグローバル レジスタを使用するなどが挙げられます。 PHP7 のパフォーマンスの最適化は継続されます。
PHP7-alpha は、PHP5.6 と比較してほぼ 3 倍のパフォーマンスが向上しています。以下は、PHP7 での WordPress のパフォーマンスです:
PHP7 の新機能
パフォーマンスの最適化に加えて、PHP7 には 2 つの重要な新機能が追加されました。
変数型
PHP7版関数のパラメータと戻り値に型修飾が追加されました。なぜ PHP は型を追加する必要があるのでしょうか? 実際、この機能は、型を追加した後、PHP JIT が変数の型を正確に判断し、最適な機械語命令を生成できるようにするためです。
関数テスト(int $a, string $b, array $c) : int {
//code
}
エラー例外
PHP プログラム エラーの後、Zend エンジンは致命的なエラーを起こし、PHP7 を使用してエラーを捕捉できました。基礎となるメソッドは、致命的エラーの代わりに例外を使用します。この特徴は、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 ソリューションを放棄しました。 0-最終バージョンには 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 に一連の非同期 IO、イベント駆動型、並列データ構造関数を提供する標準 PHP 拡張機能です。
Swoole は、Swoole が並列処理の基礎的なサポートを提供することを除いて、Node.js と非常によく似ています。 Node.js は単一プロセス、単一スレッドのプログラムであるため、マルチコア サーバー上のすべての CPU コアの計算能力を使用することはできません。プログラムがマルチコアを利用できるように、プログラマは child_process/cluster を使用して複数のインスタンスを展開または起動する必要があります。 Swoole は最下位レベルでマルチスレッド/マルチプロセスをサポートしており、プログラムが開始されると、複数の IO スレッドと複数のワーカー プロセスが作成されます。プログラマはスレッド/プロセスの数を設定するだけで済みます。
Swoole によって開発された TCP サーバー プログラムを使用します:
$serv = new swoole_server("127.0.0.1", 9501);
$serv->on('接続 ', 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 内でイベント ループを実行するため、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("
$http->start ( );
PHP の将来
PHP 言語は将来的にパフォーマンスが大幅に向上し、C/C++ や Java などの静的にコンパイルされた言語にますます近づくことが予測されます。 Swoole 拡張機能と組み合わせることで、PHP の使用範囲は、モバイル通信、クラウド コンピューティング、オンライン ゲーム、モノのインターネット、車両のインターネット、スマート ホームなどの分野に拡張できます。
PHP は最良のプログラミング言語ではないかもしれませんが、PHP はこの方向に向かって発展しています。