ホームページ >バックエンド開発 >PHPチュートリアル >PHP で大きなファイルをロードする場合の require と file_get_contents のパフォーマンスの比較
開発プロセス中に、require を使用して大規模 (数百 K、場合によっては数メガバイト) の構成ファイルをロードすると、応答タイムアウトが発生することがわかりました。この構成ファイルの内容をシリアル化し、file_get_contents を使用してファイルを取得し、それを逆シリアル化してロードすると、はるかに高速になります。
約 2 週間の調査を経て、その理由がおおよそわかりました。
まずはPHPの処理から始めましょう。 PHPには実は起動処理とリクエストに応答する処理の2つがあります。 Apache のモジュールとして、PHP は Apache に 2 つの関数を登録しています。1 つは Apache の起動時に実行される関数です: sapi_startup; もう 1 つは Apache がリクエストを受信したときに呼び出す関数です: php_handler
起動プロセス:
Apache の起動
- -> sapi_startup
- -> php_module_startup (PHP 起動マスター スイッチ)
- -> zend_startup (グローバル変数の初期化、コンパイルおよび実行関数の初期化を含む)リクエストプロセス:
Apache がリクエストを受信します
-> sapi_startup
- -> zend_activate (初期化コンパイラ、初期化エグゼキュータ、起動スキャナを含む)
- -> )
;-& Gt; Zend_execute (各 OPCODE を実行します)-& gt; Zend_deactive (このリクエストで使用されたデータを消去します)
Require または Include などの関数が見つかった場合は、ZEND_EXECUTE ステージから ZEND_compiler ステージに戻ります。 、PHP の説明を開始し、PHP のプロセスを実行します
zend_compiler と zend_execute ステージを除いて、require と file_get_contents のオーバーヘッドは基本的に同じですそして、apc 拡張機能がサーバーにインストールされます。ステージはどちらも同じと考えられます
次に、パフォーマンスの違いは zend_execute ステージにあります
まず、vld 拡張子を使用して、2 つのファイルによって生成されたオペコードの数を確認してみましょう。
結果は、生成されたオペコードの数が 20,000 を超えていることを示していますが、そのほとんどはデータを構築するためのものですが、file_get_contents は 6 つのオペコードのみを生成します。これら 2 つの関数の実行は 2 つの部分に分けることができます: ファイルを取得し、構成ファイルに配列を構築します
最初にファイルの読み取りについて説明します。必要な読み取りメカニズムは、バッファーを使用してファイルをメモリに読み取ることです。 8192 バイトのループ。一方、file_get_contents は mmap を使用してファイルを仮想メモリに直接マッピングします。この場合、require には file_get_contents よりも多くのシステム コールが必要になります。 File_get_contents は、ユーザー モードとカーネル モードの間でそれほど多くの切り替えを行う必要はありません。このステップでは、file_get_contents が勝ちます。
構築配列をもう一度見てみましょう。require 構築のメカニズムは、file_get_contents が受信テキストを解析する unserialize 関数を使用する間に、20,000 を超えるオペコードを生成することです。その後、レベルごとに配列が構築されます。配列を構築するという考え方は同じですが、require の各追加データのオーバーヘッドは unserialize のオーバーヘッドよりも大きくなります。このラウンドでは file_get_contents の方がわずかに優れています
ただし、file_get_contents は PHP 内の関数呼び出しです。そして、 require は組み込みの opcode であるため、 file_get_contents を呼び出すときのオーバーヘッドは、 require よりわずかに大きくなります
そのため、ファイルが小さい場合、 file_get_contents がファイルを読み取るときのメモリ マッピングの利点を活かすことができません。ファイルが大きい場合、require には 2K2K が必要となるため、2 つは部分的に等しくなります。read システム コールをループするとパフォーマンスが低下します。