7

入力パラメータとして数百万文字*(通常は512文字未満の文字列(Unicode))を取り込んで、それらを.net文字列として変換および保存する必要があるアプリケーションがあります。

それは私のアプリケーションのパフォーマンスの本当のボトルネックであることが判明しました。より効率的にするためのデザインパターンやアイデアはあるのでしょうか。

改善できると感じさせる重要な部分があります。重複がたくさんあります。100万個のオブジェクトが入ってくるとすると、50個のユニークなchar*パターンしかないかもしれません。

ちなみに、char *をstringに変換するために使用しているアルゴリズムは次のとおりです(このアルゴリズムは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

4 に答える 4

5

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

擬似コード:

  • 空のトライから始めて、
  • それ以上行けなくなるまでトライを検索してchar*を処理します
  • char*全体がノードとしてエンコードされるまでノードを追加します
  • リーフに、実際の.NET文字列を添付します

この他のSOの質問への答えはあなたが始めるはずです:C#でトライを作成する方法

于 2013-01-14T19:54:46.557 に答える
3

改善できると感じさせる重要な部分があります。重複がたくさんあります。100万個のオブジェクトが入ってくるとすると、50個のユニークなchar*パターンしかないかもしれません。

この場合、「見つかった」パターンをマップ内に保存することを検討し(std::map<const char*, gcroot<String^>>[の比較子が必要ですがconst char*)、それを使用して以前に変換された値を返すことができます。

マップの保存、比較の実行などにはオーバーヘッドがあります。ただし、これは、メモリ使用量を大幅に削減し(管理対象文字列インスタンスを再利用できます)、メモリ割り当てを節約する(calloc / free)ことで軽減できます。また、mallocの代わりにを使用するcallocと、を呼び出す前にメモリをゼロにする必要がないため、(非常に小さな)改善になる可能性がありますMultiByteToWideChar

于 2013-01-14T19:53:53.777 に答える
2

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

ソース文字列の長さを一度計算して明示的に渡すことで、時間を節約することもできます。そうすれば、MultiByteToWideCharstrlenを呼び出すたびに実行する必要がなくなります。

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

ここで使用できるキャッシュデータ構造が、大きな違いを生むとは思えません。

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

于 2013-01-14T20:00:29.440 に答える
1

おそらく、三分木構造などに基づくキャッシュを使用し、入力文字列を調べて、単一の文字を.NET表現に変換する前に、すでに変換されているかどうかを確認します。

于 2013-01-14T19:52:41.297 に答える