2 日前、グループの友人が私とチャットしに来ました。インタビュー中に、パフォーマンス最適化手法にどう対応するか尋ねられました。今日は話しましょう。 この記事では主に理論分析に焦点を当てていますが、Java のパフォーマンス最適化全体に従うことができるルールを見てみましょう。
この記事は理論に焦点を当てています。 実践に関しては、後続の記事でより多くの事例を使用して、この記事の知識ポイントを洗練させます。繰り返し考えたりまとめたりするのに適しています。
ご覧のとおり、最適化手法はコンピューティング リソースとストレージ リソースの計画に焦点を当てています。最適化手法で空間を時間を交換する方法はたくさんありますが、複雑さや空間の問題を考慮せずに計算速度だけを考慮することはお勧めできません。私たちがしなければならないのは、パフォーマンスを考慮しながら最適なリソース使用率を達成することです。
次に、これら 7 つの最適化の方向性を簡単に紹介します。この記事の目的は、総合スコアの概念と理論的基礎を全体的に理解していただくことです。
このアイデアは再利用です。上記の説明はコーディング ロジックの最適化ですが、データ アクセスについても同様の再利用状況が発生します。生活でもコーディングでも、常に同じことが繰り返されるため、再利用がなければ、仕事も生活もさらに疲れてしまいます。
ソフトウェア システムでは、データの再利用というと、最初にバッファリングとキャッシュが思い浮かびます。この 2 つの言葉の違いに注意してください。意味が全く異なるため、混同しやすい学生も多いです。簡単に説明します。
バッファ (バッファ) は、データを一時的に保存し、バッチで転送または書き込みするために一般的に使用されます。シーケンシャル方式は主に、異なるデバイス間の頻繁で遅いランダム書き込みを軽減するために使用され、バッファリングは主に書き込み操作を対象としています。
キャッシュ(Cache)は、読み出したデータを再利用する際によく使われる手法で、比較的高速な領域にキャッシュすることで、主に読み出し動作を対象としています。
同様に、Java で頻繁に使用されるデータベース接続プール、スレッド プールなどのオブジェクトのプーリング操作です。これらのオブジェクトは作成・破棄コストが比較的高いため、使用後も一時的に保管しておくことで、次回使用する際に再度初期化という手間のかかる作業を行う必要がなくなります。
計算のもう 1 つの最適化は、同期から非同期への変更です。これには通常、プログラミング モデルの変更が伴います。同期モードでは、成功または失敗の結果が返されるまでリクエストはブロックされます。そのプログラミング モデルは単純ですが、期間内に突然の偏ったトラフィックを処理する場合に特に問題が発生し、リクエストが簡単に失敗する可能性があります。
非同期操作は、水平方向の拡張を簡単にサポートし、瞬間的なプレッシャーを軽減し、リクエストをスムーズに行うことができます。同期リクエストは拳で鉄板を叩くようなもので、非同期リクエストは拳でスポンジを叩くようなものです。このプロセスは想像できると思いますが、後者の方が間違いなく柔軟で、エクスペリエンスがよりユーザーフレンドリーです。
最後の 1 つは、いくつかの一般的なデザイン パターンを使用してビジネスを最適化し、エクスペリエンスを向上させることです。たとえば、シングルトン モード、プロキシ モードなどです。たとえば、Swing ウィンドウを描画するときに、より多くの画像を表示したい場合は、最初にプレースホルダーを読み込み、次にバックグラウンド スレッドを通じて必要なリソースをゆっくりと読み込むことができます。これにより、ウィンドウのフリーズを回避できます。
次に、結果セットの最適化について紹介します。より直観的な例を挙げると、XML の表現が非常に優れていることは誰もが知っていますが、なぜまだ JSON が存在するのでしょうか?書きやすいことに加えて、サイズが小さくなり、送信効率と解析効率が高くなったことも重要な理由であり、Google の Protobuf と同様にサイズはさらに小さくなっています。可読性は低下しますが、一部の同時実行性の高いシナリオ (RPC など) では、効率が大幅に向上する可能性があり、これは結果セットの一般的な最適化です。
これは、現在の Web サービスがすべて C/S モードであるためです。サーバーからクライアントにデータを送信する場合、複数のコピーを分散する必要があるため、データ量は急速に増大し、少量のストレージが削減されるたびに、送信パフォーマンスとコストが大幅に増加します。
Nginx と同様に、GZIP 圧縮は通常、送信されるコンテンツをコンパクトに保つためにオンになります。クライアントは、解凍を容易にするために少量の計算能力のみを必要とします。この操作は分散化されているため、パフォーマンス上のペナルティは固定されています。
この原則を理解すると、結果セットの最適化に関する一般的な考え方がわかり、返されるデータを可能な限りシンプルにする必要があります。クライアントに必要のないフィールドがある場合は、コード内で削除するか、SQL クエリ内で直接削除します。
適時性についてはそれほど高い要件はないが、処理能力については高い要件がある一部の企業向け。バッファーの経験から学び、ネットワーク接続の相互作用を最小限に抑え、バッチ処理を使用して処理速度を向上させる必要があります。
結果セットは 2 回使用される可能性が高いため、キャッシュに追加することもできますが、それでも速度が不足しています。このとき、データ アクセスを高速化するには、インデックスまたは Bitmap ビットマップを使用してデータ収集の処理を最適化する必要があります。
通常の開発では、多くの共有リソースが関係します。これらの共有リソースには、HashMap などのスタンドアロンのもの、データベース行などの外部ストレージ、特定の Redis キーの Setnx などの単一リソース、トランザクションなどの複数のリソースの調整などがあります。 、分散トランザクションなど。
実際には、ロックに関連するパフォーマンスの問題が数多くあります。私たちのほとんどは、データベースの行ロック、テーブル ロック、Java のさまざまなロックなどを思い浮かべます。 CPU コマンド レベルのロック、JVM 命令レベルのロック、オペレーティング システムの内部ロックなどの下位レベルでは、それらはあらゆる場所に存在すると言えます。
リソースの競合が発生する可能性があるのは同時実行性のみです。つまり、同時に共有リソースを取得できる処理要求は 1 つだけです。リソースの競合を解決する方法はロックです。もう 1 つの例はトランザクションです。これは本質的にロックの一種です。
ロック レベルに応じて、ロックは楽観的ロックと悲観的ロックに分類できます。楽観的ロックの方が確実に効率的です。ロックの種類に応じて、ロックは公正なロックと不公平なロックに分類されます。スケジュールに関しては、いくつかの微妙な違いがあります。
リソースの競合はパフォーマンスに重大な問題を引き起こすため、ロックフリーのキューに関する研究が行われ、パフォーマンスが大幅に向上するでしょう。
アルゴリズムは複雑なビジネスのパフォーマンスを大幅に向上させることができますが、実際のビジネスでは、それは亜種です。ストレージがますます安価になるにつれて、CPU が非常に不足している一部のビジネスでは、処理を高速化するためにスペースを時間と引き換えにすることがよくあります。
アルゴリズムはコード チューニングに属します。これには多くのコーディング スキルが必要であり、ユーザーは使用される言語の API に精通している必要があります。場合によっては、アルゴリズムとデータ構造を柔軟に使用することもコード最適化の重要な部分となります。たとえば、時間の複雑さを軽減するために一般的に使用される方法には、再帰、二分、並べ替え、動的プログラミングなどが含まれます。
優れた実装は、不十分な実装よりもシステムに大きな影響を与えます。たとえば、List の実装として、LinkedList と ArrayList はランダム アクセスのパフォーマンスが数桁異なります。別の例として、CopyOnWriteList はコピーオンライトを使用するため、読み取りが多く書き込みが少ないシナリオでのロックの競合を大幅に減らすことができます。同期をいつ使用するか、またスレッドセーフにするかについては、コーディング機能に対するより高い要件も必要になります。
この部分は日々の業務の中での蓄積に注意が必要ですが、以降の授業ではさらに重要な知識を取り上げ、解説を散りばめていきます。
以上がインタビュー: Java パフォーマンスの最適化にどのような方法が利用できるか知っていますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。