PHP アプリケーションのパフォーマンスの最適化
PHP でプログラミングする最大の利点は、このプログラミング言語とその豊富なライブラリを簡単に学習できることです。使用する必要がある機能についてあまり知らなくても、特定のタスクを達成する方法を推測することができます。
PHP は非常にシンプルで習得が簡単ですが、PHP のプログラミング スキル、特にパフォーマンスとメモリ使用量に関連するスキルを学ぶには少し時間を費やす必要があります。 PHP には、メモリ使用量を削減し、アプリケーションのパフォーマンスを向上させるための工夫がたくさんあります。この記事では、PHP アプリケーションの分析、スクリプト コードの変更方法、および最適化前後のさまざまなパラメーター値の比較について簡単に紹介します。
プログラムにタイミング プロシージャを設定し、これらのコードを繰り返し実行することで、プログラムの実行速度に関する一連のデータを取得でき、このデータを使用してプログラムのボトルネックを発見し、パフォーマンスを向上させる最適化方法を検討できます。応用。
おそらく読者は PEAR ライブラリについて聞いたことがあるでしょう。 PEAR ライブラリを使用して、分析中に使用する必要があるサンプルを作成します。これは、商用製品を使用せずにコードを分析する最も簡単な方法でもあります。
使用するライブラリの名前は PEAR::Benchmark で、コードのプロファイリングとパフォーマンス テストに非常に役立ちます。このライブラリは、ある関数呼び出しと次の関数呼び出しの間の時間を記録できる Benchmark_Timer() という名前のクラスを提供します。コードのパフォーマンスをテストすると、次のように非常に簡単な詳細なスクリプト実行結果を取得できます。
include_once("Benchmark/Timer.php");
$bench = 新しい Benchmark_Timer;
$bench->start();
$bench-> setMarker('スクリプトの開始');
// 数分間スリープ状態になります
スリープ(5);
$bench->stop();
// タイマーから解析情報を取得
print_r($bench->getProfiling());
?>
上記のコードを実行した後の出力は次のようになります。
配列
(
[0] => 配列
(
[名前] => 開始
[時間] => 1013214253.05751200
[差分] => -
[合計] => 0
)
[1] => 配列
(
[名前] => スクリプトの開始
[時間] => 1013214253.05761100
[差分] => 9.8943710327148E-05
[合計] => 9.8943710327148E-05
)
[2] => 配列
(
[名前] => 停止
[時間] => 1013214258.04920700
[差分] => 4.9915959835052
[合計] => 4.9916949272156
)
)
上記の数値はばらばらの数値の集合のように見えるかもしれませんが、プログラムのサイズが大きい場合、これらの数値は非常に役立ちます。
おそらく読者の大多数は、配列の最初のエントリが Benchmark_Timer() クラスを呼び出す実際のメソッドであることも推測できるでしょう。
$bench->start()、$bench->setMarker()、および $bench->stop() これらのエントリに関連付けられた数値は非常に単純です。次に、これらの数値を詳しく見てみましょう。
[0] => 配列
(
[名前] => 開始
[時間] => 1013214253.05751200
[差分] => -
[合計] => 0
)
時間エントリは、Benchmark_Timer() の start() メソッドが呼び出されたときの UNIX タイムスタンプを参照します。diff エントリは、この呼び出しと最後の呼び出しの間の時間間隔を示します。ここでは、ダッシュ、合計エントリが示されます。テストの開始からこの特定の呼び出しまでコードが実行されていた合計時間を指します。次の配列の出力を見てみましょう。
[1] => 配列
(
[名前] => スクリプトの開始
[時間] => 1013214253.05761100
[差分] => 9.8943710327148E-05
[合計] => 9.8943710327148E-05
)
上記の数字から、$bench->start() を呼び出した後、$bench->setMarker(….) を呼び出す前にプログラムが 9.8943710327148E-05 秒 (つまり 0.0000989 秒) 実行されることがわかります。
実際のパフォーマンステスト体験
上記の例は優れていますが、サイトのコード設計を最適化する方法を決定するのにはあまり良い例ではありません。以下では、Web サイト技術者としての私自身の個人的な経験を使用して、パフォーマンスの問題を解決する方法を説明します。
Web サイトで使用されているコードがよくわかりません。Web サイトは特定のニーズに基づいて長年にわたって開発されてきたためです。1 つのモジュールには Web サイト変換コードが含まれ、別のモジュールには Web サイトの使用状況が記録され、他のモジュールには独自のコードが含まれています。それぞれの役割。 Web サイトの主な開発者と私は、Web サイトのコードを最適化する必要があることに気づきましたが、何が問題なのかはわかりませんでした。
できるだけ早くタスクを完了するために、Web サイトのメイン スクリプト コードの調査を開始し、すべてのスクリプト コードとそれに含まれるファイルにいくつかの $bench->setMarker() コマンドを追加してから、$bench の出力を分析しました。 ->getProfiling() を実行すると、その結果に驚きました。問題は、何百回も使用された特定の言語名 (英語の en など) を取得するための変換コードに関連する関数呼び出しにあることがわかりました。各ページにあります。この関数が呼び出されるたびに、スクリプト コードは MySQL データベースにクエリを実行して、データベース テーブルから実際の言語名を取得します。
そこで、この種の情報用のバッファリング システムを作成します。わずか 2 日間の作業でシステムのパフォーマンスが大幅に向上し、最初の 1 週間でページビュー数が 40% 増加しました。もちろん、これはコードを分析することでインターネット アプリケーションやインターネット Web サイトのパフォーマンスがどのように向上するかを示す一例にすぎません。
パフォーマンス テスト関数呼び出し
Benchmark_Timer() は、スクリプトまたは Web ページ (およびそれに含まれるファイル) を分析する場合に特に便利ですが、分析されたデータを取得するためにスクリプトを複数回ロードする必要があり、特定のクラスまたは関数に固有ではないため、科学的ではありません。と呼ばれる。
Benchmark_Iterator と呼ばれる PEAR::Benchmark ライブラリの別のクラスは、特定の関数またはクラス メソッドの分析情報を表示できます。その目的は、スクリプトを 1 回実行して実行に 10 秒かかったとしても、毎回実行に常に 10 秒かかるとは限らないことがわかっているため、テストから一貫した結果を取得できるようにすることです。
いずれにせよ、いくつかの例を見てみましょう。
// データベースに接続するコード
include_once("DB.php");
$dsn = 配列(
'phptype' => 'mysql',
'ホストスペック' => 'ローカルホスト',
'データベース' => 'データベース名',
'ユーザー名' => 'ユーザー名',
「パスワード」 => 「パスワード」
);
$dbh = DB::connect($dsn);
関数 getCreatedDate($id)
{
グローバル $dbh;
> $stmt = "ユーザーから作成日を選択 WHERE id=$id";
// ここでは PEAR::DB を使用します
$created_date = $dbh-> getOne($stmt);
if ((PEAR::isError($created_date)) ||
(空($created_date))) {
false を返します。
} それ以外 {
$created_date を返します。
}
}
include_once 'Benchmark/Iterate.php';
$bench = 新しい Benchmark_Iterate;
// getDate 関数を 10 回実行します
$bench-> run(10, 'getCreatedDate', 1);
//解析情報を出力する
print_r($bench->get());
?>
上記のコードを実行すると、次のような結果が生成されます。
配列
(
[1] => 0.055413007736206
[2] => 0.0012860298156738
[3] => 0.0010279417037964
[4] => 0.00093603134155273
[5] => 0.00094103813171387
[6] => 0.00092899799346924
[7] => 0.0010659694671631
[8] => 0.00096404552459717
[9] => 0.0010690689086914
[10] => 0.00093603134155273
[平均] => 0.0064568161964417
[反復] => 10
)
上記の数値は、getCreatedDate() 関数の 10 回の実行の平均時間を表しているため、理解しやすいです。実際のテストでは、少なくとも 1000 回は実行する必要がありますが、この例の結果は問題を説明するのに十分です。