2012-07-18 11 views
9

私はストレステストクライアントを構築しています。ストレステストクライアントは、サーバーを叩き、クライアントが召喚できる数だけスレッドを使用して応答を分析します。私は自分自身がガベージコレクション(および/またはその欠如)によって常に抑制されていると思っています。ほとんどの場合、文字列はRegexまたはXml解析ルーチンに渡すことをインスタンス化しています。あなたが正規表現クラスをコンパイルした場合StringBuilderまたはStreamsの周りにRegexおよび/またはXmlパーサを実装した人はいますか?

、あなたはが内部、それはほとんどすべてを行うためにStringBuildersを使用していることがわかりますが、あなたがすることはできませんパスその文字列ビルダ。それは有用に、それらを使用する前にプライベートメソッドに潜んでいるので、拡張メソッドもそれを解決するつもりはありません。 System.Xml.Linqのパーサからオブジェクトグラフを取得したい場合は、同様の状況にあります。

これは、事前の過大な過最適化のケースではありません。私はRegex replacements inside a StringBuilderの質問などを見てきました。私は天井の場所を知るためにアプリケーションをプロファイリングしています。Regex.Replace()は、今や1時間に何百万というリクエストでサーバーにヒットしようとしているメソッドチェーンに大きなオーバーヘッドをもたらしています。および埋め込まれた診断コード。私はすでにスループットを抑えている他のすべての非効率性を取り除きました。また、キャプチャグループや後方参照を必要としないときに、StringBuilderを拡張してワイルドカードの検索/置換を行うことで、しかし、私は、誰かが今のところカスタムStringBuilder(またはより良いストリーム)ベースのRegexとXml解析ユーティリティをラップしていると思われます。

だから、うんざりだけど、私はこれを自分でしなければならないのだろうか?

アップデート:ピークメモリ消費量を複数のギガバイトから数百megsに下げる回避策が見つかりましたので、私はそれを下に掲載しています。私は答えとして追加していません。なぜなら、私は一般的にそれをしたくないからです。そして、b)私がする前に誰かがStringBuilderをカスタマイズしてRegexesをカスタマイズするかどうかを知りたいのです。

私の場合、特定の要素に無効なバイナリコンテンツが含まれているため、私はXmlReaderを使用できませんでした。 XMLを解析するには、それらの要素を空にしなければなりません。私は以前、単一の静的コンパイル済みのRegexインスタンスを使用して置換を行いました。このようなメモリを使用していました(私は約300KBの文書を処理しようとしています)。大幅に消費電力を削減変更されました:

  1. が、私は便利なIndexOf方法のために、このStringBuilder Extensions article on CodeProjectからのコードを追加しました。
  2. 私は問題のある要素
の内容物を空に WildcardReplace()呼び出しで正規表現の使用を交換呼び出し
  • ごとにワイルドカード文字(*または?)を可能にする(非常に)粗WildcardReplaceメソッドを追加

    これは、私自身の目的が必要な限り、非常に簡単でテストされています。私はそれをよりエレガントでパワフルにしたでしょうが、YAGNIとすべてのこと、そして私は急いでいます。コードは次のとおりです。

    /// <summary> 
    /// Performs basic wildcard find and replace on a string builder, observing one of two 
    /// wildcard characters: * matches any number of characters, or ? matches a single character. 
    /// Operates on only one wildcard per invocation; 2 or more wildcards in <paramref name="find"/> 
    /// will cause an exception. 
    /// All characters in <paramref name="replaceWith"/> are treated as literal parts of 
    /// the replacement text. 
    /// </summary> 
    /// <param name="find"></param> 
    /// <param name="replaceWith"></param> 
    /// <returns></returns> 
    public static StringBuilder WildcardReplace(this StringBuilder sb, string find, string replaceWith) { 
        if (find.Split(new char[] { '*' }).Length > 2 || find.Split(new char[] { '?' }).Length > 2 || (find.Contains("*") && find.Contains("?"))) { 
         throw new ArgumentException("Only one wildcard is supported, but more than one was supplied.", "find"); 
        } 
        // are we matching one character, or any number? 
        bool matchOneCharacter = find.Contains("?"); 
        string[] parts = matchOneCharacter ? 
         find.Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries) 
         : find.Split(new char[] { '*' }, StringSplitOptions.RemoveEmptyEntries); 
        int startItemIdx; 
        int endItemIdx; 
        int newStartIdx = 0; 
        int length; 
        while ((startItemIdx = sb.IndexOf(parts[0], newStartIdx)) > 0 
         && (endItemIdx = sb.IndexOf(parts[1], startItemIdx + parts[0].Length)) > 0) { 
         length = (endItemIdx + parts[1].Length) - startItemIdx; 
         newStartIdx = startItemIdx + replaceWith.Length; 
         // With "?" wildcard, find parameter length should equal the length of its match: 
         if (matchOneCharacter && length > find.Length) 
          break; 
         sb.Remove(startItemIdx, length); 
         sb.Insert(startItemIdx, replaceWith); 
        } 
        return sb; 
    } 
    
  • +2

    生データを保存して後で分析することは可能ですか?私はこのアプローチを取った何らかの分析を見てきました... – Andre

    +0

    @Andre、ええ、これはおそらく良い提案ですが、私が解明しなければならないすべての論理のために、これまで避けてきました。現在の戦略は、非同期的にすべてを解析し、必要なオブジェクトグラフを応答から取り出し、後でより深い分析のためにMongoDBにスローすることです。 Regexが依存しているすべてのものを逆コンパイルすることなく、.Replace()を呼び出すために必要なものをすべてカスタマイズしなければ、それは次善のオプションです。プレロールされたソリューションを誰も気づかれなければ、私はその決定をしなければならないと思う。 –

    +0

    正規表現に 'RegexOptions.Compiled'を使い、サーバガベージコレクタを使うという2つの最適化について言及していません。それらの両方をやったことがありますか? –

    答えて

    関連する問題