Windows 上の Apache は動作が異なります。 Apache は子プロセスを使用する代わりにスレッドを使用します。上記のパラメータは使用されません。代わりに、デフォルトで 50 に設定される ThreadsPerChild という 1 つのパラメータがあります。このパラメータは、Apache によって生成されるスレッドの数を設定します。 Windows バージョンには子プロセスが 1 つしかないため、デフォルト設定の 50 は、50 個の同時 HTTP リクエストのみを処理できることを意味します。 Web サーバーのトラフィックが多い場合は、この値を 256 から 1024 まで増やしてください。
SendBufferSize | OS のデフォルトに設定します | TCP/IP 接続で使用される出力バッファのサイズ (バイト単位) を決定します。これは主に、パケットをバッファリングする必要がある混雑したネットワークや遅いネットワークで役立ちます。次に、このパラメータを、通常ダウンロードされる最大のファイルのサイズに近い値に設定します。クライアント接続ごとに 1 つの TCP/IP バッファが作成されます。元の HTTP 仕様では、すべての HTTP リクエストはサーバーへの個別の接続を確立する必要がありました。頻繁な接続のオーバーヘッドを軽減するために、キープアライブ ヘッダーが開発されました。キープアライブは、複数の HTTP リクエストに対して同じソケット接続を再利用するようにサーバーに指示します。 別の専用 Web サーバーがすべての画像を提供する場合は、このオプションを無効にすることができます。この技術により、リソースの使用率が大幅に向上します。 |
KeepAliveTimeout | 15 | ソケット接続を維持する秒数。この時間には、サーバーによるコンテンツの生成とクライアントによる確認が含まれます。クライアントが時間内に応答しない場合は、新しい接続を作成する必要があります。 |
そうしないとソケットが長時間アイドル状態になるため、この値は低く保つ必要があります。 | MaxKeepAliveRequests | 100 MaxKeepAliveRequests で設定されたリクエスト数に達すると、ソケット接続は終了します。 MaxClients または ThreadsPerChild. |
TimeOut | 300 | アイドル時間がこの値を超えると切断します。クライアントの待ち時間が短い場合は、この値をより低く設定できます。 |
LimitRequestBody | 0 | PUT または POST の最大サイズ。 ○は制限がないことを意味します。 |
DNS ルックアップが必要なく、htaccess ファイルを使用して個々のディレクトリの Apache 設定を構成していない場合は、以下を設定できます:
# DNS ルックアップを無効にする: PHP スクリプトは IP アドレスのみを取得します
HostnameLookups off
# disable htaccessチェック
<ディレクトリ />
AllowOverride none
シンボリック リンクにアクセスするときにディレクトリのセキュリティを心配しない場合は、追加の lstat() システム コールが行われないように、FollowSymLinks をオンにし、SymLinksIfOwnerMatch をオフにします。
Options FollowSymLinks
#Options SymLinksIfOwnerMatch
(b) IISチューニング
IIS は、Windows NT および 2000 で使用できるマルチスレッド Web サーバーです。インターネット サービス マネージャーから、次のパラメータを調整できます:
1 日あたりのヒット数に基づくパフォーマンス チューニング。 | IIS に事前に割り当てるメモリの量を決定します。 ([パフォーマンス] タブ)。 |
帯域幅調整 | Web サイトごとに割り当てられる 1 秒あたりの帯域幅を制御します。 ([パフォーマンス] タブ)。 |
プロセス スロットル | Web サイトごとに使用可能な CPU% を制御します。 ([パフォーマンス] タブ)。 |
タイムアウト | デフォルトは 900 秒です。ローカル エリア ネットワークでは、より低い値に設定します。 (Web サイト タブ) |
HTTP 圧縮 | IIS 5 では、動的ページ、HTML、および画像を圧縮できます。圧縮された静的 HTML と画像をキャッシュするように構成できます。デフォルトでは、圧縮はオフになっています。 物理サーバー全体で HTTP 圧縮を有効にする必要があります。これをオンにするには、IIS コンソールを開き、サーバー (サブサイトではなく、左側のペインにあるサーバー) を右クリックし、プロパティを取得します。 [サービス] タブをクリックし、動的コンテンツを圧縮するには [アプリケーション ファイルの圧縮] を選択し、静的コンテンツを圧縮するには [静的ファイルの圧縮] を選択します。 |
Web サイトのデフォルトの分離レベルを構成することもできます。 [アプリケーション保護] の [ホーム ディレクトリ] タブで、分離レベルを定義できます。高度に分離された Web サイトは、IIS とは別のプロセスとして実行されるため、実行が遅くなります。一方、IIS プロセスで Web サイトを実行するのは最も高速ですが、Web サイトのコードに重大なバグがある場合はサーバーがダウンします。現時点では、CGI を使用して PHP Web サイトを実行するか、アプリケーション保護を高に設定して ISAPI を使用することをお勧めします。
また、regedit.exe を使用して、次の場所に保存されている IIS 5 レジストリ設定を変更することもできます:
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesInetinfoParameters
MemCacheSize | IIS がファイル キャッシュに使用するメモリの量を設定します。デフォルトでは、IIS は使用可能なメモリの 50% を使用します。 IIS がサーバー上の唯一のアプリケーションである場合は増加します。値はメガバイト単位です。 |
MaxCachedFileSize | ファイル キャッシュにキャッシュされるファイルの最大サイズをバイト単位で決定します。デフォルトは 262,144 (256K) です。 |
ObjectCacheTTL | キャッシュ内のオブジェクトがメモリに保持される時間の長さを (ミリ秒単位で) 設定します。デフォルトは 30,000 ミリ秒 (30 秒) です。 |
MaxPoolThreads | プロセッサごとに作成するプール スレッドの数を設定します。同時に実行できる CGI アプリケーションの数を決定します。デフォルトは 4 です。CGI モードで PHP を使用している場合は、この値を増やします。 |
ListenBackLog | IIS が接続キュー内で維持するアクティブなキープアライブ接続の最大数を指定します。デフォルトは 15 ですが、サポートしたい同時接続の数まで増やす必要があります。最大は 250 です。 |
このレジストリの場所に設定がない場合は、デフォルトが使用されます。
Windows での高いパフォーマンス: IIS と FastCGI
多くのテストを行った結果、IIS と FastCGI を使用することで Windows 上で最高の PHP パフォーマンスが得られることがわかりました。 CGI は、Web サーバーから外部プログラムを呼び出すためのプロトコルです。 CGI プログラムはページ要求のたびに終了するため、それほど高速ではありません。 FastCGI は、ページ リクエスト後に CGI プログラムを永続化し、新しいページ リクエストが来たときに同じ CGI プログラムを再利用することで、このプロトコルを変更して高パフォーマンスを実現します。
IIS での FastCGI のインストールは複雑であるため、EasyWindows を使用する必要があります。 PHPインストーラー。これにより、可能な限り最高のパフォーマンスを得るために、PHP、FastCGI、および Turck MMCache がインストールされます。このインストーラーは、Apache 1.3/2.0 用の PHP もインストールできます。
FastCGI に関するこのセクションは、2003 年 10 月 21 日に追加されました。
PHP4 の Zend エンジン
Zend エンジンは、PHP4 で使用される内部コンパイラおよびランタイム エンジンです。 Zeev Suraski と Andi Gutmans によって開発された Zend Engine は、彼らの名前の略称です。 PHP4 の初期の頃は、次のように動作していました:
PHP スクリプトは Zend Engine によってロードされ、Zend オペコードにコンパイルされました。オペコードは、オペレーション コードの略で、低レベルのバイナリ命令です。次に、オペコードが実行され、生成された HTML がクライアントに送信されました。オペコードは実行後にメモリからフラッシュされました。
現在、このプロセスを高速化するのに役立つ製品や技術が多数あります。次の図は、最新の PHP スクリプトがどのように動作するかを示しています。影付きのボックスはすべてオプションです。
PHP スクリプトはメモリにロードされ、Zend オペコードにコンパイルされます。これらのオペコードは、Zend Optimizer と呼ばれるオプションのピープホール オプティマイザーを使用して最適化できるようになりました。スクリプトに応じて、PHP コードの速度を 0 ~ 50% 向上させることができます。
以前は、実行後にオペコードは破棄されていました。現在は、オプションで、いくつかの代替オープンソース製品と商用クローズドソース製品である Zend Accelerator (旧名 Zend Cache) を使用して、オペコードをメモリにキャッシュできるようになりました。 Zend Optimizer と互換性のある唯一のオペコード キャッシュは、Zend Accelerator です。オペコード キャッシュは、スクリプトの読み込みとコンパイルの手順を削除することで実行を高速化します。オペコード キャッシュを使用すると、実行時間が 10 ~ 200% 改善されます。
オペコード キャッシュの場所 Zend Accelerator: Zend Engine チームによって開発された商用オペコード キャッシュ。非常に信頼性が高く、堅牢です。詳細については、http://zend.com/ を参照してください。 パフォーマンスと信頼性は、実行する PHP スクリプトに大きく依存するため、本番サーバーで使用する前に、次のオープンソース オペコード キャッシュをテストする必要があります。 Turcke MMCache: http://turck-mmcache.sourceforge.net// は保守されなくなりました。 eAccelerator を参照してください。これは、アクティブに保守されている mmcache のブランチです (2005 年 2 月 28 日追加)。 代替 PHP キャッシュ: http://apc.communityconnect.com/ PHP アクセラレータ: http://www.php-accelerator .co.uk/ AfterBurner キャッシュ: http://www.bwcache.bware.it/ |
高いパフォーマンスの秘訣の 1 つは、より高速な PHP コードを記述することではなく、生成された HTML をファイルまたは共有メモリにキャッシュすることで PHP コードの実行を回避することです。 PHP スクリプトは 1 回だけ実行されて HTML がキャプチャされ、その後のスクリプトの呼び出しではキャッシュされた HTML がロードされます。データを定期的に更新する必要がある場合、キャッシュされた HTML に有効期限値が設定されます。 HTML キャッシュは PHP 言語や Zend Engine の一部ではありませんが、PHP コードを使用して実装されます。これを行うクラス ライブラリは数多くあります。そのうちの 1 つは PEAR キャッシュです。これについては次のセクションで説明します。もう 1 つは、Smarty テンプレート ライブラリです。
最後に、Web クライアントに送信される HTML を圧縮できます。これを有効にするには、PHP スクリプトの先頭に次のコードを配置します。
ob_start("ob_gzhandler");
:
:
?>
HTML の圧縮率が高い場合は、HTML ファイルのサイズを 50 ~ 80% 削減して、ネットワーク帯域幅の要件と遅延を軽減することができます。欠点は、圧縮のためにある程度の CPU パワーを確保する必要があることです。
PEAR キャッシュを使用した HTML キャッシュ
PEAR キャッシュは、HTML や画像などの複数のタイプのデータをキャッシュできるようにする一連のキャッシュ クラスです。
PEAR キャッシュの最も一般的な用途は、HTML テキストをキャッシュすることです。これを行うには、start() 関数と end() 関数の間で出力またはエコーされたすべてのテキストをキャッシュする出力バッファリング クラスを使用します。 file", array("cache_dir" => "cache/") );
if ($contents = $cache->start(md5("これは一意のキーです!"))) {
#
# ああ、キャッシュされたデータが返されました#
print $contents;
print "
キャッシュ ヒット
";
} else {
#
# キャッシュ データがないか、キャッシュの有効期限が切れています#
print "
これを持たずに家を出ないでください…
"; # キャッシュに配置します
print "立って配達
"; # キャッシュに配置します
print $cache->end(10); }
これらの行を書いて以来、優れた PEAR キャッシュ システムが開発されました。より高度な分散キャッシュについては、memcached (2005 年 2 月 28 日追加) を参照してください。
Cache コンストラクターは、最初のパラメーターとして使用するストレージ ドライバーを受け取ります。ファイル、データベース、および共有メモリのストレージ ドライバーが利用可能です。 pear/Cache/Container ディレクトリを参照してください。 Ulf Wendel によるベンチマークは、「ファイル」ストレージ ドライバーが最高のパフォーマンスを提供することを示唆しています。 2 番目のパラメータはストレージ ドライバのオプションです。オプションは、キャッシュ ディレクトリの場所である「cache_dir」と、キャッシュされたすべてのファイルに使用するプレフィックスである「filename_prefix」です。奇妙なことに、キャッシュの有効期限はオプション パラメーターに設定されていません。
一部のデータをキャッシュするには、キーを使用してキャッシュされたデータの一意の ID を生成します。上の例では、md5("this is a unique key!") を使用しました。
start() 関数は、キーを使用してコンテンツのキャッシュされたコピーを検索します。コンテンツがキャッシュされていない場合、start() によって空の文字列が返され、end() が呼び出されるまで、以降のすべての echo() および print() ステートメントが出力キャッシュにバッファリングされます。
end() 関数はバッファの内容を返し、出力バッファリングを終了します。 end() 関数は、最初のパラメータとしてキャッシュの有効期限を受け取ります。このパラメータには、データをキャッシュする秒数、データの有効期限を指定する Unix 整数タイムスタンプ、またはデフォルトの 24 時間のゼロを指定できます。
PEAR キャッシュを使用する別の方法は、変数またはその他のデータを保存することです。 。これを行うには、基本 Cache クラスを使用できます:
require_once("Cache.php");
$cache = new Cache("file", array("cache_dir" => ")キャッシュ/") );
$id = $cache->generateID("これは一意のキーです");
if ($data = $cache->get($id)) {
print "キャッシュhit.
Data: $data";
} else {
$data = "慈悲の質は緊張しない...";
$cache->save($id, $data, $期限切れ = 60); print "キャッシュミス。
";
}
?>
データを保存するには、save() を使用します。一意のキーがすでに有効なファイル名である場合は、generateID() ステップをバイパスできます。 save() がデータをシリアル化するため、オブジェクトと配列を保存できます。最後のパラメータは、データの有効期限がいつ切れるかを制御します。これは、データをキャッシュする秒数、またはデータの有効期限が切れる日時を指定する Unix 整数タイムスタンプ、またはデフォルトの 24 時間を使用する場合はゼロにすることができます。キャッシュされたデータを取得するには、get() を使用します。
$cache->delete($id) を使用してキャッシュされたデータ項目を削除でき、$cache->flush() を使用してキャッシュされたすべての項目を削除できます。
新機能: より高速なキャッシュ クラスは Cache-Lite です。強くお勧めします。
ベンチマークの使用
前のセクションでは、パフォーマンスに関する多くの問題について説明しました。ここで、本質的な部分に移ります。つまり、何を調整すべきかについて適切な情報を取得できるように、コードの測定とベンチマークを行う方法です。
Web サーバー上で現実的なベンチマークを実行したい場合は、HTTP リクエストをサーバーに送信するツールが必要になります。 Unix では、ベンチマークを実行する一般的なツールには、Apache リリースの一部である ab (apachebench の略) と、新しいフラッド (httpd.apache.org/test/flood) が含まれます。 Windows NT/2000 では、Microsoft の無料の Web Application Stress Tool (webtool.rte.microsoft.com) を使用できます。
これらのプログラムは、複数の HTTP リクエストを同時に作成し、複数の Web クライアントをシミュレートし、リクエストの完了に関する詳細な統計を表示できます。テスト
「vmstat 1」を使用して Unix 上でベンチマークが実行されるときにサーバーがどのように動作するかを監視できます。これにより、ディスク I/O、仮想メモリ、CPU 負荷のパフォーマンスに関するステータス レポートが毎秒出力されます。あるいは、「top d 1」を使用すると、実行中のすべてのプロセスが CPU 負荷別にソートされて 1 秒ごとに全画面更新されます。
Windows 2000 では、パフォーマンス モニターまたはタスク マネージャーを使用してシステム統計を表示できます。
HTTP オーバーヘッドを気にせずにコードの特定の側面をテストしたい場合は、マイクロタイムを使用してベンチマークを実行できます。 () は、マイクロ秒単位の正確な現在時刻を文字列として返します。次の関数は、計算に適した数値に変換します。
function getmicrotime()
{
list($usec, $sec) =explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
$time = getmicrotime();
#
# ベンチマークコードはこちら
#
echo "
経過時間: ", getmicrotime() - $time, " 秒";
あるいは、APD や XDebug などのプロファイリング ツールを使用することもできます。 xdebug を使用してコードを圧縮する私の記事も参照してください。
ベンチマークのケーススタディ
このケーススタディでは、クライアントのために行った実際のベンチマークについて詳しく説明します。この例では、顧客は、長い SQL クエリの実行を含まないすべての PHP ページに対して 5 秒の応答時間を保証したいと考えていました。次のサーバー構成が使用されました: Red Hat 7.2 Linux 上で PHP 4.0.6 を実行する Apache 1.3.20 サーバー。ハードウェアは、1 Gb の RAM を備えたツイン Pentium III 933 MHz の野獣でした。 HTTP リクエストは、PHP スクリプト「testmysql.php」に対するものになります。このスクリプトは、別のサーバーで実行されている MySQL データベースから約 20 レコードを読み取り、処理します。簡単にするために、すべてのグラフィックスが別の Web サーバーからダウンロードされると仮定します。
ベンチマーク ツールとして「ab」を使用しました。 10 の同時接続 (-c10) を使用して、1000 のリクエスト (-n1000) を実行するように「ab」を設定します。結果は次のとおりです。
# ab -n1000 -c10 http://192.168.0.99/php/testmysql.phpThis is ApacheBench, Version 1.3Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/Copyright (c) 1998-1999 The Apache Group, http://www.apache.org/Server Software: Apache/1.3.20Server Hostname: 192.168.0.99Server Port: 80Document Path: /php/testmysql.phpDocument Length: 25970 bytesConcurrency Level: 10Time taken for tests: 128.672 secondsComplete requests: 1000Failed requests: 0Total transferred: 26382000 bytesHTML transferred: 25970000 bytesRequests per second: 7.77Transfer rate: 205.03 kb/s receivedConnnection Times (ms) min avg maxConnect: 0 9 114Processing: 698 1274 2071Total: 698 1283 2185
ログイン後にコピー
ベンチマークの実行中、サーバー側でコマンド「top d 1」を使用してリソース使用率を監視しました。パラメータ「d 1」は、更新の間に 1 秒の遅延を意味します。出力を以下に示します。
10:58pm up 3:36, 2 users, load average: 9.07, 3.29, 1.7974 processes: 63 sleeping, 11 running, 0 zombie, 0 stoppedCPU0 states: 92.0% user, 7.0% system, 0.0% nice, 0.0% idleCPU1 states: 95.0% user, 4.0% system, 0.0% nice, 0.0% idleMem: 1028484K av, 230324K used, 798160K free, 64K shrd, 27196K buffSwap: 2040244K av, 0K used, 2040244K free 30360K cached PID USER PRI NI SIZE RSS SHARE STAT %CPU %MEM TIME COMMAND 1142 apache 20 0 7280 7280 3780 R 21.2 0.7 0:20 httpd 1154 apache 17 0 8044 8044 3788 S 19.3 0.7 0:20 httpd 1155 apache 20 0 8052 8052 3796 R 19.3 0.7 0:20 httpd 1141 apache 15 0 6764 6764 3780 S 14.7 0.6 0:20 httpd 1174 apache 14 0 6848 6848 3788 S 12.9 0.6 0:20 httpd 1178 apache 13 0 6864 6864 3804 S 12.9 0.6 0:19 httpd 1157 apache 15 0 7536 7536 3788 R 11.0 0.7 0:19 httpd 1159 apache 15 0 7540 7540 3788 R 11.0 0.7 0:19 httpd 1148 apache 11 0 6672 6672 3784 S 10.1 0.6 0:20 httpd 1158 apache 14 0 7400 7400 3788 R 10.1 0.7 0:19 httpd 1163 apache 20 0 7540 7540 3788 R 10.1 0.7 0:19 httpd 1169 apache 12 0 6856 6856 3796 S 10.1 0.6 0:20 httpd 1176 apache 16 0 8052 8052 3796 R 10.1 0.7 0:19 httpd 1171 apache 15 0 7984 7984 3780 S 9.2 0.7 0:18 httpd 1170 apache 16 0 7204 7204 3796 R 6.4 0.7 0:20 httpd 1168 apache 10 0 6856 6856 3796 S 4.6 0.6 0:20 httpd 1377 natsoft 11 0 1104 1104 856 R 2.7 0.1 0:02 top 1152 apache 9 0 6752 6752 3788 S 1.8 0.6 0:20 httpd 1167 apache 9 0 6848 6848 3788 S 0.9 0.6 0:19 httpd 1 root 8 0 520 520 452 S 0.0 0.0 0:04 init 2 root 9 0 0 0 0 SW 0.0 0.0 0:00 keventd
ログイン後にコピー
"top" の出力を見ると、ツイン CPU の Apache サーバーはアイドル時間 0% でフル稼働しています。さらに悪いのは、負荷平均が過去 1 分間で 9.07 (過去 5 分間で 3.29、過去 15 分間で 1.79) であることです。負荷平均は、実行準備ができているプロセスの平均数です。ツイン プロセッサ サーバーの場合、負荷が 2.0 を超えると、システムが過負荷になっていることを意味します。負荷 (9.07) と ab. で定義した同時接続数 (10) の間に密接な関係があることに気づくかもしれません
幸いなことに、約 798,160 MB の空き容量があり、仮想メモリは使用されていないため、十分な物理メモリがあります。 .
さらに下では、CPU 使用率の順にプロセスが表示されます。最もアクティブなものは Apache httpd プロセスです。最初の httpd タスクは 7280K のメモリを使用し、平均して CPU の 21.2%、物理メモリの 0.7% を占有しています。 STAT 列はステータスを示します。R は実行可能、S はスリープ、W はプロセスがスワップアウトされていることを意味します。
上記の数値を考慮し、これが典型的なピーク負荷であると仮定すると、いくつかの計画を実行できます。ツイン CPU サーバーの負荷平均が 9.0 で、各タスクの完了にほぼ同じ時間がかかると仮定すると、負荷の軽いサーバーは 9.0 / 2 CPU = 4.5 倍高速になるはずです。したがって、ピーク負荷時に応答するのに 1.283 秒かかっていた HTTP リクエストは、完了するまでに約 1.283 / 4.5 = 0.285 秒かかります。
To verify this, we benchmarked with 2 simultaneous client connections (instead of 10 in the previous benchmark) to give an average of 0.281 seconds, very close to the 0.285 seconds prediction!
# ab -n100 -c2 http://192.168.0.99/php/testmysql.php [ some lines omitted for brevity ]Requests per second: 7.10Transfer rate: 187.37 kb/s receivedConnnection Times (ms) min avg maxConnect: 0 2 40Processing: 255 279 292Total: 255 281 332
ログイン後にコピー
Conversely, doubling the connections, we can predict that the average connection time should double from 1.283 to 2.566 seconds. In the benchmarks, the actual time was 2.570 seconds.
Overload on 40 connections
When we pushed the benchmark to use 40 connections, the server overloaded with 35% failed requests. On further investigation, it was because the MySQL server persistent connects were failing because of "Too Many Connections".
The benchmark also demonstrates the lingering behavior of Apache child processes. Each PHP script uses 2 persistent connections, so at 40 connections, we should only be using at most 80 persistent connections, well below the default MySQL max_connections of 100. However Apache idle child processes are not assigned immediately to new requests due to latencies, keep-alives and other technical reasons; these lingering child processes held the remaining 20+ persistent connections that were "the straws that broke the Camel's back".
The Fix
By switching to non-persistent database connections, we were able to fix this problem and obtained a result of 5.340 seconds. An alternative solution would have been to increase the MySQL max_connections parameter from the default of 100.
Conclusions
The above case study once again shows us that optimizing your performance is extremely complex. It requires an understanding of multiple software subsystems including network routing, the TCP/IP stack, the amount of physical and virtual memory, the number of CPUs, the behavior of Apache child processes, your PHP scripts, and the database configuration.
In this case the PHP code was quite well tuned, so the first bottleneck was the CPU, which caused a slowdown in response time. As the load increased, the system slowed down in a near linear fashion (which is a good sign) until we encountered the more serious bottleneck of MySQL client connections. This caused multiple errors in our PHP pages until we fixed it by switching to non-persistent connections.
From the above figures, we can calculate for a given desired response time, how many simultaneous HTTP connections we can handle. Assuming two-way network latencies of 0.5 seconds on the Internet (0.25s one way), we can predict:
As our client wanted a maximum response time of 5 seconds, the server can handle up to 34 simultaneous connections per second. This works out to a peak capacity of 34/5 = 6.8 page views per second.
To get the maximum number of page views a day that the server can handle, multiply the peak capacity per second by 50,000 (this technique is suggested by the webmasters at pair.com, a large web hosting company), to give 340,000 page views a day.
Code Optimizations
The patient reader who is still wondering why so much emphasis is given to discussing non-PHP issues is reminded that PHP is a fast language, and many of the likely bottlenecks causing slow speeds lie outside PHP.
Most PHP scripts are simple. They involve reading some session information, loading some data from a content management system or database, formatting the appropriate HTML and echoing the results to the HTTP client. Assuming that a typical PHP script completes in 0.1 seconds and the Internet latency is 0.2 seconds, only 33% of the 0.3 seconds response time that the HTTP client sees is actual PHP computation. So if you improve a script's speed by 20%, the HTTP client will see response times drop to 0.28 seconds, which is an insignificant improvement. Of course the server can probably handle 20% more requests for the same page, so scalability has improved.
The above example does not mean we should throw our hands up and give up. It means that we should not feel proud tweaking the last 1% of speed from our code, but we should spend our time optimizing worthwhile areas of our code to get higher returns.
High Return Code Optimizations
The places where such high returns are achievable are in the while and for loops that litter our code, where each slowdown in the code is magnified by the number of times we iterate over them. The best way of understanding what can be optimized is to use a few examples:
Example 1
Here is one simple example that prints an array:
for ($j=0; $j echo $arr[$j]."
";
This can be substantially speeded up by changing the code to:
for ($j=0, $max = sizeof($arr), $s = ''; $j<$max; $j++)
$s .= $arr[$j]."
";
echo $s;
まず、式 $j 2 番目の問題は、PHP 4 では、複数回エコーする方が、すべてを文字列に保存して 1 回の呼び出しでエコーするよりも遅いということです。これは、エコーは HTTP クライアントへの TCP/IP パケットの送信を伴う可能性がある高価な操作であるためです。もちろん、$s に文字列を蓄積すると、より多くのメモリを使用するため、スケーラビリティの問題がいくつか発生します。そのため、ここにはトレードオフが関係していることがわかります。
上記のコードを高速化する別の方法は、出力バッファリングを使用することです。これにより、出力文字列が内部的に蓄積され、スクリプトの最後で出力が一度に送信されます。これにより、メモリの増加と遅延の増加を犠牲にして、ネットワークのオーバーヘッドが大幅に削減されます。完全に echo ステートメントで構成されたコードの一部では、15% のパフォーマンスの向上が観察されました。
ob_start();
for ($j=0, $max = sizeof($arr), $s = ''; $j<$max; $j++)
echo $arr[$j]."< br>";
ob_start() による出力バッファリングは、すべての PHP スクリプトのグローバル最適化として使用できることに注意してください。長時間実行されるスクリプトでは、出力バッファを定期的にフラッシュして、何らかのフィードバックが HTTP クライアントに送信されるようにすることもできます。これは ob_end_flush() で実行できます。この関数は出力バッファリングもオフにするため、フラッシュの直後に ob_start() を再度呼び出すことをお勧めします。
要約すると、この例では、ループの不変条件を最適化する方法と、出力バッファリングを使用してコードを高速化する方法を示しました。
例 2
次のコードでは、特別なフォーマット関数を使用して行をフォーマットし、PEAR DB レコードセットを反復処理し、結果をエコーします。今回は 10.2 ミリ秒で実行時間をベンチマークしました (これにはデータベース接続と SQL 実行時間は含まれません):
function FormatRow(&$recordSet)
{
$arr = $recordSet->fetchRow();
return ' '.$arr[0].''.$arr[1].'';
}
for ($j = 0; $ j < $rs->numRows(); $j++) {
print FormatRow($rs);
}
例 1 から、コードを次のように変更することでコードを最適化できることがわかりました (実行時間: 8.7 ミリ秒):
function FormatRow(&$recordSet){
$arr = $recordSet->fetchRow();
return ''.$arr[0].' '.$arr[1].'';
}
ob_start();
for ($j = 0, $max = $rs->numRows(); $ j < $max; $j++) { print FormatRow($rs);
}
私のベンチマークでは、$max を使用すると 0.5 ミリ秒、ob_start を使用すると 1.5 ミリ秒の高速化に寄与することがわかりました。ループアルゴリズムを変更すると、コードを簡素化して高速化できます。この場合、実行時間は 8.5 ミリ秒に短縮されます:
function FormatRow($arr){
return ''.$arr[0].''.$ arr[1].';}
ob_start();
while ($arr = $rs->fetchRow()) { print FormatRow($arr);
}
One最後の最適化はここで可能です。関数呼び出しのオーバーヘッド (速度のために保守性が犠牲になる可能性があります) を削除して、さらに 0.1 ミリ秒 (実行時間: 8.4 ミリ秒) を短縮できます。 )) {
print ''.$arr[0].''.$arr[1].'';
}
切り替えることでPEAR キャッシュに移行すると、キャッシュされたデータの実行時間は再び 3.5 ミリ秒に低下しました:
require_once("Cache/Output.php");
ob_start();
$cache = new Cache_Output("file", array("cache_dir) " => "cache/") );
$t = getmicrotime();
if ($contents = $cache->start(md5("this is a unique kexy!"))) { print "
キャッシュ ヒット
";
print $contents;} else {
print "キャッシュ ミス
";
#### データベースに接続してクエリを実行するコード省略
##
while ($arr = $rs->fetchRow()) {
print ''.$arr[0].''.$arr [1].'';
}
print $cache->end(100);
}
print (getmicrotime()-$t);
最適化方法を以下にまとめます。
実行時間 (ms)
最適化方法
9.9 | 初期コード、最適化なし、データベース接続と SQL 実行時間を除く |
9.2 | ob_start の使用 |
8.7 | ループの最適化不変式 ($max) を使用し、ob_start |
8.5 | for ループから while ループに変更し、配列を FormatRow() に渡し、ob_start |
8 を使用します。 4
| FormatRow() の削除と ob_start の使用 |
3.5 | PEAR Cache の使用と ob_start の使用 |
上の図から、最大の速度向上は t によるものではないことがわかります。コードを弱め、ただし、ob_start() などの単純なグローバル最適化、または HTML キャッシュなどの根本的に異なるアルゴリズムを使用します。
オブジェクト指向プログラミングの最適化 2001 年 3 月、私は PHP 4.0.4pl1 のクラスで非公式のベンチマークをいくつか実施しました。そしてその結果からいくつかのアドバイスを導き出しました。主なポイントは次の 3 つです: 1.使用する前にすべての変数を初期化します。 2.値に 2 回以上アクセスする予定がある場合は、メソッドで頻繁に使用されるすべてのグローバル/プロパティ変数を逆参照し、値をローカル変数に入れます。 3.頻繁に使用するメソッドを派生クラスに配置してみてください。 警告: PHP は継続的な改善プロセスを経ているため、将来状況が変わる可能性があります。 詳細 オブジェクト メソッド (クラスで定義された関数) の呼び出しは、通常の関数の約 2 倍遅いことがわかりました。呼び出します。私にとって、これは非常に許容できるものであり、他の OOP 言語と同等です。 Inside 刷新评论 刷新页面 返顶部 博客园首页 博问 新闻闪存 程序员招聘 知识库
|
Powered by: 博客园 Copyright © moris |