ホームページ  >  記事  >  バックエンド開発  >  [转]PHP の最適化に関する HOWTO

[转]PHP の最適化に関する HOWTO

WBOY
WBOYオリジナル
2016-06-23 14:32:19764ブラウズ

来源:http://phplens.com/lens/php-book/optimizing-debugging-php.php

最終改訂日 2005 年 2 月 28 日。変更内容を確認したい場合は、この日付を検索してください。この記事。

この記事が気に入ったら、私のブログ、PHP Everywhere にアクセスして関連記事をご覧ください。

PHP の最適化に関する HOWTO

PHP は非常に高速なプログラミング言語ですが、PHP の最適化にはコードの実行速度だけではありません。

この章では、PHP の最適化にコードとは関係のない多くの要素が関係する理由、および PHP のチューニングにサーバー上の他のすべてのサブシステムとの関係で PHP がどのように動作するかを理解し、これらのサブシステムによって引き起こされるボトルネックを特定して修正する必要がある理由を説明します。彼ら。また、PHP スクリプトをさらに高速に実行できるように調整および最適化する方法についても説明します。

高いパフォーマンスの達成

優れたパフォーマンスについて話すとき、PHP スクリプトの実行速度について話しているのではありません。パフォーマンスは、スケーラビリティと速度の間の一連のトレードオフです。使用するリソースが少なくなるように調整されたスクリプトは、キャッシュを実行するスクリプトよりも遅くなる可能性がありますが、同じスクリプトのより多くのコピーを Web サーバー上で一度に実行できます。

以下の例では、A.php は速く走ることができる短距離ランナーであり、B.php はほぼ同じ速度で永遠にジョギングできるマラソンランナーです。負荷が軽い場合は、A.php の方が大幅に高速ですが、Web トラフィックが増加すると、B.php のパフォーマンスが少し低下するだけで、A.php は力不足になるだけです。

より現実的な例を見てみましょう。問題をさらに明確にするため。 250K ファイルを読み取り、ファイルの HTML 概要を生成する PHP スクリプトを作成する必要があるとします。同じことを行う 2 つのスクリプトを作成します。hare.php はファイル全体を一度にメモリに読み込み、1 回のパスで処理します。もう 1 つは、一度に 1 行ずつファイルを読み込み、最長行以上は保持しない tortoise.php です。記憶の中で。 Tortoise.php は複数の読み取りが発行されるため遅くなり、より多くのシステムコールが必要になります。

Hare.php は 0.04 秒の CPU と 10 Mb RAM を必要とし、tortoise.php は 0.06 秒の CPU と 5 Mb RAM を必要とします。サーバーには 100 MB の実際の空き RAM があり、CPU は 99% アイドル状態です。話を単純化するために、メモリの断片化が発生しないと仮定します。

10 個のスクリプトを同時に実行すると、hare.php がメモリ不足になります (10 x 10 = 100)。この時点では、tortoise.php にはまだ 50 MB の空きメモリが残っています。 11 番目の同時スクリプトを実行すると、hare.php が仮想メモリの使用を開始し、速度が元の半分程度に低下します。 hare.php の各呼び出しには 0.08 秒の CPU 時間がかかるようになりました。その間、tortoise.php は引き続き通常の 0.06 秒の CPU 時間で実行されます。

以下の表では、さまざまな負荷に対する高速な php スクリプトが太字で示されています:

0.88tortoise.php 0.06 0.60 0.66

上記の例が示すように、優れたパフォーマンスを得るには、単に高速な PHP スクリプトを作成する必要があります。高性能 PHP を使用するには、基盤となるハードウェア、オペレーティング システム、および Web サーバーやデータベースなどのサポート ソフトウェアをよく理解する必要があります。

ボトルネック

ウサギとカメの例は、ボトルネックが速度低下の原因であることを示しています。無限の RAM を使用すると、hare.php は常に tortoise.php より高速になります。残念ながら、上記のモデルは少し単純化されており、RAM 以外にもパフォーマンスに対するボトルネックが多数あります。

(a) ネットワーク

ネットワークがおそらく最大のボトルネックです。インターネットへの 10 M ビットのリンクがあり、1 秒あたり 1 メガバイトのデータを送信できるとします。各 Web ページが 30k の場合、1 秒あたりわずか 33 Web ページで回線が飽和状態になります。

さらに微妙なネットワークのボトルネックには、DNS などの遅いネットワーク サービスへの頻繁なアクセスや、ネットワーク ソフトウェアへの不十分なメモリの割り当てが含まれます。

(b) CPU

CPU 負荷を監視している場合、ネットワーク経由でプレーン HTML ページを送信しても負担はかかりません前述したように、ボトルネックはネットワークであるため、CPU はまったく必要ありません。ただし、PHP が生成する複雑な動的 Web ページの場合は、通常、CPU 速度が制限要因になります。複数のプロセッサを備えたサーバーを使用するか、サーバー ファームを使用すると、この問題を軽減できます。

(c) 共有メモリ

共有メモリはプロセス間通信に使用され、キャッシュされたデータやコードなどの複数のプロセス間で共有されるリソースを保存します。 。共有メモリが十分に割り当てられていない場合、データベース接続や実行可能コードなどの共有メモリを使用するリソースにアクセスしようとすると、パフォーマンスが低下します。

(d) ファイル システム

ハードディスクへのアクセスは、ハードディスクからのデータの読み取りよりも 50 ~ 100 倍遅くなる可能性があります。ラム。 RAM を使用したファイル キャッシュを使用すると、これを軽減できます。ただし、メモリが少ない状態では、ファイル システム キャッシュに使用できるメモリの量が減少し、動作が遅くなります。ファイル システムが大幅に断片化し、ディスク アクセスが遅くなる場合もあります。 Unix システムでシンボリック リンクを頻繁に使用すると、ディスク アクセスも遅くなる可能性があります。

デフォルトの Linux インストールは、速度ではなく互換性を重視して調整されたハードディスクのデフォルト設定を設定していることでも知られています。 Linux ハードディスク設定を調整するには、hdparm コマンドを使用します。

(e) プロセス管理

Windows などの一部のオペレーティング システムでは、新しいプロセスの作成に時間がかかります。つまり、呼び出されるたびに新しいプロセスをフォークする CGI アプリケーションは、これらのオペレーティング システムでは実行速度が大幅に遅くなります。 PHP をマルチスレッド モードで実行すると、応答時間が改善されます (注: 古いバージョンの PHP はマルチスレッド モードでは安定しません)。

不要なプロセスが多すぎて Web サーバーが過密になることを避けてください。たとえば、サーバーが純粋に Web サービスを目的としている場合は、マシン上で X-Windows を実行 (またはインストール) することは避けてください。 Windows では、CPU 使用率が 100% になる Microsoft Find Fast (Office の一部) および 3D スクリーン セーバーの実行を避けてください。

削除を検討できるプログラムには、未使用のネットワーク プロトコル、メール サーバー、ウイルス対策スキャナ、ハードウェアなどがあります。マウス、赤外線ポートなどのドライバー。 Unix では、SSH を使用してサーバーにアクセスしていると思います。次に、以下を削除することを検討できます:

telnetd、inetd、atd、ftpd、lpd、sambad などのデーモン

受信メールの sendmail
NFS のポートマップ
xfs、fvwm、xinit、X

起動時にさまざまなプログラムを無効にすることもできます。通常、/etc/init* または /etc/rc*/init* ディレクトリに保存されている起動ファイルを変更します。

cron ジョブを確認して、それらを削除できるか、オフピーク期間にスケジュールを変更できるかどうかを確認してください。

(f) 他のサーバーへの接続

Web サーバーが他のサーバーで実行されているサービスを必要とする場合、それらのジョブが他のサーバーで実行されている可能性があります。サーバーがボトルネックになります。この最も一般的な例は、複数の Web サーバーからのあまりにも多くの複雑な SQL リクエストを処理している遅いデータベース サーバーです。完了です。このアドバイスが意味をなすのは、プログラミング チームのコーディングがそもそも高品質であり、アプリケーションのパフォーマンス パラメータをすでに十分に把握している場合のみです。そうしないと、テスト後にコードのかなりの部分を書き直さなければならないというリスクにさらされることになります。

私のアドバイスは、ソフトウェア アプリケーションを設計する前に、ハードウェアとソフトウェアの基本的なベンチマークをいくつか実行して、動作の感触を掴む必要があるということです。達成できる可能性のある最大限のパフォーマンス。次に、アプリケーションを設計してコーディングする際には、必要なパフォーマンス パラメーターを念頭に置いてください。これは、あらゆる段階で、パフォーマンス、可用性、セキュリティ、柔軟性の間にトレードオフが存在するためです。

接続

1 つの HTTP リクエストを満たすのに必要な CPU 秒数

10 の HTTP リクエストを満たすのに必要な CPU 秒数

11 の HTTP リクエストを満たすのに必要な CPU 秒数

hare.php

0.04

0.40

(RAM が不足しています)


また、適切なテストデータを選択してください。データベースが 100,000 レコードを保持すると予想される場合は、100 レコードのデータベースだけを使用したテストを避けてください。後悔するでしょう。かつて、私の会社のプログラマーの一人にこのようなことが起こりました。遅いコードはかなり後になってから検出され、機能しても拡張できなかった多くのコードを書き直す必要があったため、多くの時間が無駄になりました。現在使用されている 2 つの最も一般的な Web サーバー、Apache 1.3 と IIS で最高の PHP パフォーマンスを得る方法を説明します。ここでのアドバイスの多くは、HTML の提供にも当てはまります。

PHP の作成者は、PHP で Apache 1.3 よりも Apache 2.0 を使用する場合、特にマルチスレッド モードでパフォーマンスやスケーラビリティの利点がないと述べています。 Apache 2.0 をプリフォーク モードで実行する場合、次の議論は依然として重要です (2003 年 10 月 21 日)。
(a) Apache 1.3/2.0

Apache は Unix と Windows の両方で使用できます。世界で最も人気のある Web サーバーです。 Apache 1.3 は、Web サービスに事前フォーク モデルを使用します。 Apache が起動すると、HTTP リクエストを処理する複数の子プロセスが作成されます。最初の親プロセスは守護天使のように機能し、すべての子プロセスが適切に動作していることを確認し、すべてを調整します。より多くの HTTP リクエストが受信されると、それらを処理するためにより多くの子プロセスが生成されます。 HTTP リクエストが遅くなると、親プロセスはアイドル状態の子プロセスを強制終了し、他のプロセスのリソースを解放します。このスキームの利点は、Apache を非常に堅牢にすることです。子プロセスがクラッシュした場合でも、親プロセスと他の子プロセスはクラッシュした子プロセスから隔離されます。

プリフォークモデルは他の考えられる設計ほど高速ではありませんが、私にとっては「大した問題ではない」と思います。 Apache のパフォーマンスの問題が重大になるずっと前に、他のボトルネックが発生するため、PHP スクリプトを提供するサーバーでは実行できません。 Apache の堅牢性と信頼性はより重要です。

Apache 2.0 はマルチスレッド モードでの操作を提供します。私のベンチマークによると、このモードではパフォーマンス上の利点がほとんどありません。また、多くの PHP 拡張機能には互換性がないことにも注意してください (GD や IMAP など)。 Apache 2.0.47 (2003 年 10 月 21 日) でテスト済み。

Apache は httpd.conf ファイルを使用して設定されています。次のパラメータは、子プロセスの設定において特に重要です:

Directive

Default

Description

MaxClients

256
子プロセスの最大数作成する。デフォルトは、最大 256 の HTTP リクエストを同時に処理できることを意味します。それ以降の接続要求はキューに入れられます。

StartServers

5
起動時に作成する子プロセスの数。

MinSpareServers

5
作成する必要があるアイドル状態の子プロセスの数。アイドル状態の子プロセスの数がこの数を下回ると、最初に 1 つの子が作成され、次の 2 秒後に 2 つ、さらに 1 秒後に 4 つというように、1 秒あたり 32 の子が作成されるまで続きます。

MaxSpareServers

10
この数を超える子プロセスが生きている場合、これらの余分なプロセスは終了されます。

MaxRequestsPerChild

0
子が終了するまでに処理できる HTTP リクエストの数を設定します。 0 に設定すると、決して終了しないことを意味します。メモリ リークが発生していると思われる場合、または十分に活用されていないリソースを解放するには、これを 100 ~ 10000 の値に設定します。

大規模なサイトの場合は、次の値に近い値が適している可能性があります:

MinSpareServers 32

MaxSpareServers 64

Windows 上の Apache は動作が異なります。 Apache は子プロセスを使用する代わりにスレッドを使用します。上記のパラメータは使用されません。代わりに、デフォルトで 50 に設定される ThreadsPerChild という 1 つのパラメータがあります。このパラメータは、Apache によって生成されるスレッドの数を設定します。 Windows バージョンには子プロセスが 1 つしかないため、デフォルト設定の 50 は、50 個の同時 HTTP リクエストのみを処理できることを意味します。 Web サーバーのトラフィックが多い場合は、この値を 256 から 1024 まで増やしてください。

変更できるその他の便利なパフォーマンス パラメータには次のものがあります。

そうしないとソケットが長時間アイドル状態になるため、この値は低く保つ必要があります。

DNS ルックアップが必要なく、htaccess ファイルを使用して個々のディレクトリの Apache 設定を構成していない場合は、以下を設定できます:

# DNS ルックアップを無効にする: PHP スクリプトは IP アドレスのみを取得します

HostnameLookups off

# disable htaccessチェック

b49aa56367fdeb85a9496dde3971aec7

AllowOverride none

bb15ed4aadeed04b3991578461de0768

シンボリック リンクにアクセスするときにディレクトリのセキュリティを心配しない場合は、追加の lstat() システム コールが行われないように、FollowSymLinks をオンにし、SymLinksIfOwnerMatch をオフにします。

Options FollowSymLinks

#Options SymLinksIfOwnerMatch

(b) IISチューニング

IIS は、Windows NT および 2000 で使用できるマルチスレッド Web サーバーです。インターネット サービス マネージャーから、次のパラメータを調整できます:

SendBufferSize

OS のデフォルトに設定します

TCP/IP 接続で使用される出力バッファのサイズ (バイト単位) を決定します。これは主に、パケットをバッファリングする必要がある混雑したネットワークや遅いネットワークで役立ちます。次に、このパラメータを、通常ダウンロードされる最大のファイルのサイズに近い値に設定します。クライアント接続ごとに 1 つの TCP/IP バッファが作成されます。元の HTTP 仕様では、すべての HTTP リクエストはサーバーへの個別の接続を確立する必要がありました。頻繁な接続のオーバーヘッドを軽減するために、キープアライブ ヘッダーが開発されました。キープアライブは、複数の HTTP リクエストに対して同じソケット接続を再利用するようにサーバーに指示します。

別の専用 Web サーバーがすべての画像を提供する場合は、このオプションを無効にすることができます。この技術により、リソースの使用率が大幅に向上します。

KeepAliveTimeout

15

ソケット接続を維持する秒数。この時間には、サーバーによるコンテンツの生成とクライアントによる確認が含まれます。クライアントが時間内に応答しない場合は、新しい接続を作成する必要があります。

MaxKeepAliveRequests

100

MaxKeepAliveRequests で設定されたリクエスト数に達すると、ソケット接続は終了します。 MaxClients または ThreadsPerChild.

TimeOut

300

アイドル時間がこの値を超えると切断します。クライアントの待機時間が短い場合は、この値をより低く設定できます。

LimitRequestBody

0

PUT または POST の最大サイズ。 ○は制限がないことを意味します。

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 スクリプトの先頭に次のコードを配置します。

76a91a73551d7a6df2440035cad9852a

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 "e388a4556c0f65e1904146cc1a846beeCache Hit94b3e26ee717c64999d7867364b1b4a3";

} else {


#

# キャッシュされたデータがないか、キャッシュの有効期限が切れています

#

print "e388a4556c0f65e1904146cc1a846beeこれを持たずに家を出ないでください…94b3e26ee717c64999d7867364b1b4a3"; # キャッシュに配置します
print "e388a4556c0f65e1904146cc1a846bee立って配達94b3e26ee717c64999d7867364b1b4a3"; # キャッシュに配置します
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 クラスを使用できます:

18ae17aa53bcf926e898f010e2408154 ")キャッシュ/") );

$id = $cache->generateID("これは一意のキーです");

if ($data = $cache->get($id)) {


print "キャッシュhit.0c6dc11e160d3b678d68754cc175188aData: $data";

} else {

$data = "慈悲の質は緊張しない...";

$cache->save($id, $data, $期限切れ = 60);

print "キャッシュミス。0c6dc11e160d3b678d68754cc175188a";

}

?>

データを保存するには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 "e388a4556c0f65e1904146cc1a846bee経過時間: ", 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 はプロセスがスワップアウトされていることを意味します。

Given the above figures, and assuming this a typical peak load, we can perform some planning. If the load average is 9.0 for a twin-CPU server and assuming each task takes about the same amount of time to complete, then a lightly loaded server should be 9.0 / 2 CPUs = 4.5 times faster. So a HTTP request that used to take 1.283 seconds to satisfy at peak load will take about 1.283 / 4.5 = 0.285 seconds to complete.

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

配列を出力する簡単な例を 1 つ示します:

for ($j=0; $j echo $arr[$j]."0c6dc11e160d3b678d68754cc175188a";

これは、コードを次のように変更することで大幅に高速化できます:

for ($j=0, $max = sizeof($arr), $s = ''; $j $s .= $arr[$j]."0c6dc11e160d3b678d68754cc175188a";

echo $s;

まず、式 $j

2 番目の問題は、PHP 4 では、複数回エコーする方が、すべてを文字列に保存して 1 回の呼び出しでエコーするよりも遅いということです。これは、エコーは HTTP クライアントへの TCP/IP パケットの送信を伴う可能性がある高価な操作であるためです。もちろん、$s に文字列を蓄積すると、より多くのメモリを使用するため、スケーラビリティの問題がいくつか発生します。そのため、ここにはトレードオフが関係していることがわかります。

上記のコードを高速化する別の方法は、出力バッファリングを使用することです。これにより、出力文字列が内部的に蓄積され、スクリプトの最後で出力が一度に送信されます。これにより、メモリの増加と遅延の増加を犠牲にして、ネットワークのオーバーヘッドが大幅に削減されます。完全に echo ステートメントで構成されたコードの一部では、15% のパフォーマンスの向上が観察されました。

ob_start();
for ($j=0, $max = sizeof($arr), $s = ''; $j echo $arr[$j]."2a87851f231f0546ed00aa1a4409038e";

ob_start() による出力バッファリングは、すべての PHP スクリプトのグローバル最適化として使用できることに注意してください。長時間実行されるスクリプトでは、出力バッファを定期的にフラッシュして、何らかのフィードバックが HTTP クライアントに送信されるようにすることもできます。これは ob_end_flush() で実行できます。この関数は出力バッファリングもオフにするため、フラッシュの直後に ob_start() を再度呼び出すことをお勧めします。

要約すると、この例では、ループの不変条件を最適化する方法と、出力バッファリングを使用してコードを高速化する方法を示しました。

例 2

次のコードでは、特別なフォーマット関数を使用して行をフォーマットし、PEAR DB レコードセットを反復処理し、結果をエコーし​​ます。今回は 10.2 ミリ秒で実行時間をベンチマークしました (これにはデータベース接続と SQL 実行時間は含まれません):

function FormatRow(&$recordSet)
{
$arr = $recordSet->fetchRow();
return ' a4b561c25d9afb9ac8dc4d70affff419'.$arr[0].'0d36329ec37a2cc24d42c7229b69747a5a8028ccc7a7e27417bff9f05adf5932'.$arr[1].'72ac96585ae54b6ae11f849d2649d9e6';
}

for ($j = 0; $ j 6e2e54331a81701d054969b57d4f9506numRows(); $j++) {
print FormatRow($rs);
}

例 1 から、コードを次のように変更することでコードを最適化できることがわかりました (実行時間: 8.7 ミリ秒):

function FormatRow(&$recordSet)
{
$arr = $recordSet->fetchRow();
return 'a4b561c25d9afb9ac8dc4d70affff419'.$arr[0].'0d36329ec37a2cc24d42c7229b69747a 5a8028ccc7a7e27417bff9f05adf5932'.$arr[1].'72ac96585ae54b6ae11f849d2649d9e6';
}

ob_start();

for ($j = 0, $max = $rs->numRows(); $ j < $max; $j++) {
print FormatRow($rs);
}

私のベンチマークでは、$max を使用すると 0.5 ミリ秒、ob_start を使用すると 1.5 ミリ秒の高速化に寄与することがわかりました。ループアルゴリズムを変更すると、コードを簡素化して高速化できます。この場合、実行時間は 8.5 ミリ秒に短縮されます。 arr[1].72ac96585ae54b6ae11f849d2649d9e6';

}

ob_start();


while ($arr = $rs->fetchRow()) {
print FormatRow($arr);
}

One最後の最適化はここで可能です。関数呼び出しのオーバーヘッド (速度のために保守性が犠牲になる可能性があります) を削除して、さらに 0.1 ミリ秒 (実行時間: 8.4 ミリ秒) を短縮できます。 )) {

print 'a4b561c25d9afb9ac8dc4d70affff419'.$arr[0].'0d36329ec37a2cc24d42c7229b69747a5a8028ccc7a7e27417bff9f05adf5932'.$arr[1].'72ac96585ae54b6ae11f849d2649d9e6';

}

切り替えることで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 "e388a4556c0f65e1904146cc1a846beeCache Hit94b3e26ee717c64999d7867364b1b4a3";

print $contents;

} else {

print "e388a4556c0f65e1904146cc1a846beeCache Miss94b3e26ee717c64999d7867364b1b4a3";

##

## データベースに接続してクエリを実行するコード省略

##

while ($arr = $rs->fetchRow()) {
print 'a4b561c25d9afb9ac8dc4d70affff419'.$arr[0].'0d36329ec37a2cc24d42c7229b69747a5a8028ccc7a7e27417bff9f05adf5932'.$arr[1].' 72ac96585ae54b6ae11f849d2649d9e6';
}

print $cache->end(100);
}

print (getmicrotime()-$t);

以下に最適化方法をまとめます:

実行時間 (ミリ秒)

最適化方法

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 を使用するキャッシュと ob_start の使用

上記の図から、次のことがわかります。速度の最大の向上は、コードの微調整によるものではなく、ob_start() などの単純なグローバル最適化、または HTML キャッシュなどの根本的に異なるアルゴリズムの使用によって得られます。 PHP 4.0.4pl1 のクラスを使用した非公式のベンチマークをいくつか実行し、その結果からいくつかのアドバイスを導き出しました。主なポイントは次の 3 つです:

1.使用する前にすべての変数を初期化します。 2.値に 2 回以上アクセスする予定がある場合は、メソッドで頻繁に使用されるすべてのグローバル/プロパティ変数を逆参照し、値をローカル変数に入れます。

3.頻繁に使用するメソッドを派生クラスに配置してみてください。

警告: PHP は継続的な改善プロセスを経ているため、将来状況が変わる可能性があります。

詳細

オブジェクト メソッド (クラスで定義された関数) の呼び出しは、通常の関数の約 2 倍遅いことがわかりました。呼び出します。私にとって、これは非常に許容できるものであり、他の OOP 言語と同等です。

メソッド内 (以下の比率はおおよその値です):

メソッド内でローカル変数をインクリメントするのが最も高速です。関数内でローカル変数を呼び出すのとほぼ同じです。グローバル変数のインクリメントは、ローカル変数の 2 倍遅くなります。オブジェクト プロパティ ($this->prop++ など) のインクリメントは、ローカル変数より 3 倍遅くなります。未定義のローカル変数のインクリメントは、事前に初期化されたローカル変数のインクリメントよりも 9 ~ 10 倍遅くなります。関数内で使用せずにグローバル変数を宣言するだけでも、処理が遅くなります (ローカル変数をインクリメントするのとほぼ同じ量)。 PHP はおそらく、グローバルが存在するかどうかを確認するチェックを行います。テスト クラスに 10 個のメソッドを (テスト メソッドの前後に) 追加しましたが、パフォーマンスに変化はなかったので、メソッドの呼び出しはクラス内で定義されたメソッドの数とは無関係であるように見えます。派生クラスのメソッドは、基本クラスで定義されたメソッドよりも高速に実行されます。 1 つのパラメーターと空の関数本体を使用した関数呼び出しには、7 ~ 8 回の $localvar++ 操作を実行するのとほぼ同じ時間がかかります。もちろん、同様のメソッド呼び出しは約 15 の $localvar++ 操作になります。

更新: 2004 年 7 月 11 日: 上記のテストは、約 3 年前に PHP 4.0.4 で行われました。これを PHP4.3.3 で再度テストしたところ、関数の呼び出しには約 20 の $localvar++ 操作が必要となり、メソッドの呼び出しには約 30 の $localvar++ 操作が必要になりました。これは、$localvar++ の実行速度が速くなったか、関数の速度が遅くなったことが原因である可能性があります。

調整の概要

使用しているソフトウェア (Apache、PHP、IIS、データベース) を理解し、オペレーティング システム、ネットワーク、およびサーバー ハードウェアについての知識が深まるほど、グローバルな最適化をより適切に実行できるようになります。コードとシステム。

PHP スクリプトの場合、通常、最もコストがかかるボトルネックは CPU です。ツイン CPU は、おそらく 2 ギガバイトの RAM よりも有用です。

「configure ?-enable-inline-optimization」オプションを使用して PHP をコンパイルし、可能な限り最速の PHP 実行可能ファイルを生成します。

データベースを調整し、SQL WHERE 条件でよく使用されるフィールドのインデックスを作成します。非常に人気のあるデータベース抽象化ライブラリである ADOdb は、SQL チューニング モードを提供します。このモードでは、無効で高価で疑わしい SQL、その実行計画、および SQL がどの PHP スクリプトで実行されたかを表示できます。

めったに変更されないデータがある場合は、HTML キャッシュを使用します。データが毎分変化する場合でも、データがキャッシュと同期されていれば、キャッシュが役に立ちます。コードの複雑さによっては、パフォーマンスが 10 倍向上する可能性があります。

最も複雑なコードを早い段階で (または少なくともプロトタイプで) ベンチマークして、修正が手遅れになる前に予想されるパフォーマンスの感触をつかみます。適切にスケールされることを確認するために、現実的な量のテスト データを使用するようにしてください。

2004 年 7 月 11 日更新: すべての関数呼び出しの実行プロファイルを使用してベンチマークを行うには、xdebug 拡張機能を試すことができます。 xdebug の使用方法の簡単なチュートリアルについては、「xdebug を使用したコードの圧縮」を参照してください。これを行うための市販の製品もあります。ゼンドスタジオ。

オペコード キャッシュの使用を検討してください。これにより、コードの複雑さに応じて 10 ~ 200% の速度向上が得られます。キャッシュの中には他のものよりも信頼性の高いものがあるため、キャッシュをインストールする前に必ずいくつかのストレス テストを実行してください。

コードの先頭で ob_start() を使用します。これにより、Apache の速度が無料で 5 ~ 15% 向上します。 gzip 圧縮を使用してダウンロードをさらに高速化することもできます (これには予備の CPU サイクルが必要です)。

Zend Optimizer のインストールを検討してください。これは無料で、いくつかの最適化を行いますが、Zend Optimizer がインストールされていると一部のスクリプトが実際に遅くなることに注意してください。コードに多数のループがある場合には、Zend Optimizer が適しているというのがコンセンサスです。現在、多くのオペコード アクセラレータが同様の機能を備えています (この文を 2003 年 10 月 21 日に追加)。

まずループを最適化します。ループの不変式 (定数) をループの外に移動します。

可能な場合は、配列関数と文字列関数を使用します。これらは、PHP で同等のコードを記述するよりも高速です。

複数の小さな文字列を 1 つの大きな文字列に連結する最も速い方法は、出力バッファ (ob_start) を作成し、そのバッファにエコーすることです。最後に、ob_get_contents を使用してコンテンツを取得します。これが機能するのは、通常、文字列連結ではメモリ割り当てが最大の要因であり、出力バッファリングでは 10K のチャンクで増加する大きな 40K の初期バッファが割り当てられるためです。 2004 年 6 月 22 日追加。

関数内の参照を使用してオブジェクトと配列を渡します。可能であれば、オブジェクトと配列も参照として返します。これが短いスクリプトであり、コードのメンテナンスが問題にならない場合は、グローバル変数を使用してオブジェクトまたは配列を保持することを検討できます。

セッション変数を使用する PHP スクリプトが多数ある場合は、セッション用の共有メモリ モジュールを使用して PHP を再コンパイルするか、RAM ディスクを使用することを検討してください。これを「configure -?with-mm」で有効にしてから PHP を再コンパイルし、php.ini で session.save_handler=mm を設定します。

部分文字列を検索する場合、最も速いコードは strpos() を使用し、次に preg_match()、最後に ereg() を使用します。同様に、str_replace() は preg_replace() より高速で、preg_replace() は ereg_replace() より高速です。

2004 年 7 月 11 日追加: 最も頻繁に発生するケースを先頭にして大きな switch ステートメントを並べます。最も一般的なケースの一部がデフォルトのセクションにある場合は、switch ステートメントの先頭でこれらのケースを明示的に定義することを検討してください。

XML を処理する場合、正規表現を使用した解析は、DOM や SAX を使用するよりも大幅に高速です。

メモリ使用量を削減するために、使用されなくなった変数を Unset() します。これは主にリソースや大規模な配列に役立ちます。

深い階層を持つクラスの場合、派生クラス (子クラス) で定義された関数は、基本クラス (親クラス) で定義された関数よりも高速に呼び出されます。基本クラスで最も頻繁に使用されるコードを派生クラスでも複製することを検討してください。

もう少し速度が必要な場合は、コードを PHP 拡張機能、Java クラス、または COM オブジェクトとして作成することを検討してください。 COM と Java の間でデータをマーシャリングするオーバーヘッドに注意してください。

無駄な最適化

Some optimizations are useful. Others are a waste of time - sometimes the improvement is neglible, and sometimes the PHP internals change, rendering the tweak obsolete.

Here are some common PHP legends:

a. echo is faster than print

Echo is supposed to be faster because it doesn't return a value while print does. From my benchmarks with PHP 4.3, the difference is neglible. And under some situations, print is faster than echo (when ob_start is enabled).

b. strip off comments to speed up code

If you use an opcode cache, comments are already ignored. This is a myth from PHP3 days, when each line of PHP was interpreted in run-time.

c. 'var='.$var is faster than "var=$var"

This used to be true in PHP 4.2 and earlier. This was fixed in PHP 4.3. Note (22 June 2004): apparently the 4.3 fix reduced the overhead, but not completely. However I find the performance difference to be negligible.

 

Do References Speed Your Code?

References do not provide any performance benefits for strings, integers and other basic data types. For example, consider the following code:

function TestRef(&$a){    $b = $a;    $c = $a;}$one = 1;ProcessArrayRef($one);

And the same code without references:

function TestNoRef($a){    $b = $a;    $c = $a;}$one = 1;ProcessArrayNoRef($one);
 

PHP does not actually create duplicate variables when "pass by value" is used, but uses high speed reference counting internally. So in TestRef(), $b and $c take longer to set because the references have to be tracked, while in TestNoRef(), $b and $c just point to the original value of $a, and the reference counter is incremented. So TestNoRef() will execute faster than TestRef().

In contrast, functions that accept array and object parameters have a performance advantage when references are used. This is because arrays and objects do not use reference counting, so multiple copies of an array or object are created if "pass by value" is used. So the following code:

function ObjRef(&$o)
{
   $a =$o->name;
}

is faster than:

$function ObjRef($o)
{
  $a = $o->name;
}

Note: In PHP 5, all objects are passed by reference automatically, without the need of an explicit & in the parameter list. PHP 5 object performance should be significantly faster.

 

Many thanks also to Andrei Zmievski for reviewing this article.

 

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。