
かつて、何年も前に、あるクライアントが私のところに来て、一つのすばらしいプロジェクトを理解し、仕事のスピードを上げる
要するに、タスクはこれでした-HTMLページを削除し、データベース(MySQL)で折りたたみを組み立てるC ++の特定のロボットがあります。 多くの機能とLAMP上のWebを使用していますが、これはストーリーとは関係ありません。
前のチームは、クラウド内の4コアXeonを管理して、 毎秒2ページという素晴らしい収集速度を実現し、コレクターと同じ種類の別のサーバー上のデータベースの両方のCPU使用率を100%にしました。
ちなみに、バンガロールの「有能なプロのチーム」は、それができないことに気付いて降伏し、散らばっていました。 ビーズのほか」(C)。
PHPとデータベーススキーマで物事を整理することの複雑さについては改めて説明しますが、ここまで来たスキルの例を1つだけ紹介します。
剖検への行き方

このような深刻なデータベースの負荷は、そもそも私に興味がありました。 詳細なロギングをオンにします。
もちろん、インターフェイスからのタスクはデータベース内で形成され、ロボットは1秒間に50回尋問しました。新しいタスクは表示されませんでしたか? さらに、データは、ロボットではなくインターフェイスに便利な方法で自然にレイアウトされます。 結果は、リクエストで3つの内部結合になります。
間隔をすぐに「1秒間に1回」増やします。 クレイジーリクエストを削除します。つまり、3つのフィールドの新しいプレートを追加し、Webからテーブルにトリガーを書き込むと、自動的に入力され、シンプルに変更されます。
select * from new_table where status = Pending
新しい状況-コレクターはまだ100%ビジーで、データベースは2%ビジーで、現在は1秒あたり4ページです。
プロファイラーをピックアップ

そして突然、ランタイムの80%がすばらしいEnterCriticalSectionメソッドとLeaveCriticalSectionメソッドで占められていることがわかりました 。 そして、それらは(予測的に)有名な会社の標準アロケーターから呼び出されます。
夕方はだらしないようになりますが、多くの仕事があり、心から書き直さなければならないことを理解しています。
そしてもちろん、私の前任者は、SAXが非常に複雑であるため、
知り合いになりましょう-私にとって何が改善されましたか?
思考光線による時期尚早な最適化の危険性

データベースが100%読み込まれたことを見て、処理のために新しいURLをリストに挿入するのは遅いと固く確信しました。
この特定のコードを最適化することで、それらを導いたものを理解することさえ難しいと感じています。 しかし、アプローチ自体! 理論的には、ここで減速していますが、まだ減速しましょう。
このために、彼らはそのようなトリックを思いつきました:
- 非同期挿入要求キュー
- メモリー内の渡されたすべてのURLを記憶する巨大なロックを備えた、メモリー内の巨大なHashMap。 また、サーバーであるため、このような最適化の後、定期的に再起動する必要がありました。 キャッシュのクリーニングを完了していません。
- たとえば、多くの魔法の定数-データベースから次のURLのバッチを処理するために、400を超えるエントリは取得されません。 なぜ400? そして拾いました。
- データベース内の「作家」の数は多く、それぞれがサイクルの中で自分の役割を果たそうとしましたが、彼は突然幸運でした。
そしてもちろん、他の多くの真珠も入手できました。
一般に、コードの進化を観察することは非常に有益でした。 ストレージのメリットを拒否することはありません。すべてが慎重にコメント化されています。 このように
void GodClass::PlaceToDB(const Foo* bar, ...) { /* 1, */ /* 2 - , */ /* 3 - , , */ .... /* N-1, , */ // - }
私は何をしましたか

もちろん、すべてのトリックはすぐに捨てられ、同期挿入を返し、重複をカットするために制約をデータベースに掛けました(巨大なロックと自己記述ハッシュマップで踊るのではなく)。
また、自動インクリメントフィールドを削除し、それらの代わりにUUIDを挿入しました(新しい値を計算するために暗黙のロックテーブルが忍び寄る場合があります)。 同時に、テーブルを大幅に削減し、1行あたり20Kに削減しました。データベースが沈んでいるのは驚くことではありません。
また、魔法の定数も削除しました。それらの代わりに、共通のタスクキューとキューを満たすための別のスレッドを持つ通常のスレッドプールを作成し、空になったりオーバーフローしたりしないようにしました。
結果は毎秒15ページです。
ただし、再プロファイリングでは画期的な改善は見られませんでした。 もちろん、アーキテクチャの改善による7倍の加速もパンですが、十分ではありません。 結局のところ、元のジャムはすべて残っていたので、最適化されたピースのみを削除して死にました。
メガバイト構造化ファイルを解析するための正規表現が悪い

私は自分の前に何が行われたのかを研究し続け、私は知らない著者のアプローチを楽しんでいます。
めでか!
トラクターの恵みにより、連中はこのようなデータを取得する問題を解決しました(それぞれに独自の正規表現のセットがあります)。
- すべてのコメントをHTMLで切り取ります
- JavaScriptコメントが切り取られました
- スクリプトタグをカット
- スタイルタグを切り取る
- 彼らは頭から2桁を取りました
- 体以外のすべてをカット
- すべての「a href」 をまとめて切り取ります
- ボディでは、不要なdivとテーブルがすべて切り取られ、写真も
- その後、テーブルレイアウトが削除されました
- 残りの部分では、タグp、strong、em、i、b、gなどが削除されました。
- 最後に、残りのプレーンテキストでは、さらに3桁の数字を取得しました
驚くべきことに、このアプローチでは、毎秒少なくとも2ページを噛みました。
チューニング後に式自体を引用していないことは明らかです-これは読みにくい波線の巨大なシートです。
それだけではありません-もちろん、正しいブーストライブラリが使用され、すべての操作はstd :: stringで実行されました( 正しく-しかし、HTMLを置く場所はどこですか?Char *は概念ではありません! これは、非常に多くのメモリ割り当てが発生する場所です。
char *とSAXスタイルのシンプルなHTMLパーサーを使用し、必要な数字を覚えて、URLを並行して引き出します。 仕事の2日間、そして見よ。
結果は1秒あたり200ページです。
すでに受け入れられますが、十分ではありません。 わずか100回。
シェルへの別のアプローチ

新しいプロファイリングの結果に目を向けます。 より良くなりましたが、まだ多くの割り当てがあり、何らかの理由でBoost to_lower()が最初に出ました。
最初に目を引くのは、Javaからシームレスに描画される強力なURLクラスです。 ええ、そうです-C ++であるため、とにかく高速になります 。 アロケーターは異なると思います 。 したがって、コピーとサブストリング()の束がヒンズー教のすべてです。 そしてもちろん、to_lowerをURL ::ホストに直接適用します-それはすべての比較と言及で必要であり、確かに後押しします。
to_lower()の過度の使用を削除し、std :: stringの代わりに再配布せずにURLをchar *に書き換えます。 同時に、数サイクルを最適化しています。
結果は1秒あたり300ページです。
これで150回の加速が達成されましたが、加速の余地はまだありました。 そして彼は2週間以上を殺しました。
結論

いつもの結論-ジャンルの古典。 パフォーマンスを評価するときにツールを使用します。頭から発明しないでください。 太陽を手動で設定する代わりに、より広い(またはより広い)既製のライブラリを使用します。
そして、