2013-01-14 16 views
7

私は入力パラメータ(通常512文字未満(ユニコード)以下)で数百万個のchar *を取り込む必要があるアプリケーションを持っています。ネット文字列。数百万のchar *を文字列変換に最適化

私のアプリケーションのパフォーマンスは、実際のボトルネックになります。私はそれがより効果的になるようなデザインパターンやアイデアがあるのだろうかと思っています。

私はそれが改善されるように感じさせる重要な部分があります:重複がたくさんあります。 100万のオブジェクトが入ってきているとすれば、50個の一意のchar *パターンのようにしか見えません。レコードの

は、ここで私は、文字列へのchar *に変換するために使用しているアルゴリズム(このアルゴリズムはC++であるが、プロジェクトの残りの部分はC#である)私はおそらく使用する

String ^StringTools::MbCharToStr (const char *Source) 
{ 
    String ^str; 

    if((Source == NULL) || (Source[0] == '\0')) 
    { 
     str = gcnew String(""); 
    } 
    else 
    { 
     // Find the number of UTF-16 characters needed to hold the 
     // converted UTF-8 string, and allocate a buffer for them. 
     const size_t max_strsize = 2048; 

     int wstr_size = MultiByteToWideChar (CP_UTF8, 0L, Source, -1, NULL, 0); 
     if (wstr_size < max_strsize) 
     { 
     // Save the malloc/free overhead if it's a reasonable size. 
     // Plus, KJN was having fits with exceptions within exception logging due 
     // to a corrupted heap. 

     wchar_t wstr[max_strsize]; 

     (void) MultiByteToWideChar (CP_UTF8, 0L, Source, -1, wstr, (int) wstr_size); 
     str = gcnew String (wstr); 
     } 
     else 
     { 
     wchar_t *wstr = (wchar_t *)calloc (wstr_size, sizeof(wchar_t)); 
     if (wstr == NULL) 
      throw gcnew PCSException (__FILE__, __LINE__, PCS_INSUF_MEMORY, MSG_SEVERE); 

     // Convert the UTF-8 string into the UTF-16 buffer, construct the 
     // result String from the UTF-16 buffer, and then free the buffer. 

     (void) MultiByteToWideChar (CP_UTF8, 0L, Source, -1, wstr, (int) wstr_size); 
     str = gcnew String (wstr); 
     free (wstr); 
     } 
    } 
    return str; 
} 
+4

C++ではなく、C++/CLIやC++/CXのようです。タグが変わっていないのは、どちらがわからないからです。 – bames53

+0

あなたは50個ほどのC#文字列とその100万回の参照で終わりたいのですか? –

+0

C++/CLIです。はい、100万回の参照があります。 – greggorob64

答えて

5

入力文字列の各文字を使用して、trie構造を供給することができます。葉には、単一の.NET文字列オブジェクトがあります。その後、以前に見たchar*が入ったら、メモリを割り当てずに既存の.NETバージョンをすばやく見つけることができます。

擬似コード:空のトライ、

  • プロセスと

    • 開始のchar *あなたがあなたの全体のchar *が符号化されているまでは、さらに
    • は、ノードを追加しない行くことができるまでトライを検索することにより、葉のノード
    • として、この他に答え、実際の.NETの文字列

    を添付SOの質問は、あなたが取得する必要starte d:How to create a trie in c#

  • +0

    これはうまくいくはずの実用的な実装だと思います。 – greggorob64

    1

    です三元ツリー構造に基づくキャッシュ、または同様のものを使用して、入力文字列をルックアップして、変換済みかどうかを調べてから、単一の文字を.NET表現に変換することもできます。

    3

    私はそれが改善されるように感じる重要な部分があります:重複がたくさんあります。 100万のオブジェクトが入ってきているとすれば、50個の一意のchar *パターンのようにしか見えません。

    このような場合は、あなたが(例えば、あなたがconst char*ための比較演算が必要になりますけれども[std::map<const char*, gcroot<String^>>を使用するなど)マップ内に「見つかった」パターンを格納考慮し、リターンにそれを使用することもできます以前に変換された値

    マップの格納や比較などのオーバーヘッドがありますが、メモリ使用量の大幅な削減(管理された文字列インスタンスの再利用が可能)、メモリ割り当ての削減(calloc /無料)。また、を呼び出す前にメモリをゼロにする必要がないので、callocの代わりにmallocを使用すると、(非常に小さい)改善になる可能性があります。

    +0

    私は確実にmallocからcallocに切り替えます。マッピングはツリー実装とよく似ていますが、.netデータ型(C++、標準C++ではなくC++)にアクセスできるため、マップ型を使用できる可能性があります。 – greggorob64

    +0

    @ greggorob64ネイティブタイプをキーにした.netコレクションでは、簡単に作業することはできません。 'std :: map'の値を' gcroot 'にすると、カスタムビルドタイプがなくても動作し、同じ' log(n) 'アクセス時間をトライとして与えます。 ;) –

    +0

    @Reed:試行は 'O(lg n)'ではなく文字列の数に関して 'O(1)'です。 –

    2

    ここで最初に最適化すると、最初にMultiByteToWideCharをNULLポインタの代わりにバッファで呼び出すようにしてみてください。 CP_UTF8を指定したため、MultiByteToWideCharは予想される長さを決定するために文字列全体を移動する必要があります。あなたの文字列の大部分より長いある長さがある場合、そのサイズのバッファを楽観的にスタックに割り当てることを検討するかもしれません。それが失敗した場合は、動的割り当てに進みます。つまり、if/elseブロックがif/elseの外側にある場合は、最初のブランチを移動します。

    また、ソース文字列の長さを1回計算して明示的に渡すことで、時間を節約することもできます。つまり、MultiByteToWideCharを呼び出すたびにstrlenを実行する必要はありません。

    あなたのプロジェクトの残りの部分がC#のように思えますが、変換する唯一の目的のためにC++/CLIでサイドバイサイドアセンブリを使用するのではなく、これを行うように設計された.NET BCLクラスライブラリを使用する必要があります文字列。それはSystem.Text.Encodingのためです。

    ここで使用できるキャッシュデータ構造の種類は、大きな違いはないと思います。

    の結果を無視しないでください。voidに何もキャストしないでください。MultiByteToWideCharが失敗した場合、未定義の動作が発生しています。

    +0

    私はsystem.text.encoding名前空間を調べます。最初に.netを使用し始めたときに、標準の文字列コンストラクタを使用しました: 新しい文字列(char * input)。これはワイド文字でかなり短時間で終わったので、上記の実装が見つかり、それを使用しています。正しい解決策は、ライブラリgivent houghを使用しています。 – greggorob64

    関連する問題