32

オープン ソースのSignalRプロジェクトのソース コードを閲覧していると、 「このホット コード パスでは StringBuilder または foreach を使用しないでください」というタイトルのこの差分コードが表示されます。

-           public static string MakeCursor(IEnumerable<Cursor> cursors)
+           public static string MakeCursor(IList<Cursor> cursors)
            { 
-               var sb = new StringBuilder();
-               bool first = true;
-               foreach (var c in cursors)
+               var result = "";
+               for (int i = 0; i < cursors.Count; i++)
                {
-                   if (!first)
+                   if (i > 0)
                    {
-                       sb.Append('|');
+                       result += '|';
                    }
-                   sb.Append(Escape(c.Key));
-                   sb.Append(',');
-                   sb.Append(c.Id);
-                   first = false;
+                   result += Escape(cursors[i].Key);
+                   result += ',';
+                   result += cursors[i].Id;
                }
-               return sb.ToString();
+               return result;
            }

foreach の効率が悪い場合がある理由と、それが for に置き換えられる理由を理解しています。

しかし、StringBuilder が文字列を連結する最も効率的な方法であることを学び、経験しました。では、なぜ著者がそれを標準の連結に置き換えることにしたのか疑問に思っています。

ここで、および StringBuilder の使用について一般的に何が問題になっていますか?

4

5 に答える 5

30

私はコードを変更しました。はい、割り当て (GetEnumerator()) 呼び出しとそうでない数に大きな違いがありました。このコードが 1 秒間に何百万回も実行されると想像してください。割り当てられた列挙子の数はばかげており、回避できます。

編集: 割り当てを回避するために制御を反転します (ライターに直接書き込みます): https://github.com/SignalR/SignalR/blob/2.0.2/src/Microsoft.AspNet.SignalR.Core/Messaging/ Cursor.cs#L36

于 2012-09-11T21:37:56.333 に答える
3

これを変更した人が実際に違いを測定したことを願っています.

  • 毎回新しい stringbuilder をインスタンス化すると、オーバーヘッドが発生します。これは、メモリ/ガベージ コレクションにも負担をかけます。
  • コンパイラは、単純な連結に対して「stringbuilderlike」コードを生成できます
  • FORは、コンパイラが境界内にあることを「認識」しているため、foreachループでは実行されない境界チェックが必要になる可能性があるため、実際には遅くなる可能性があります。
于 2012-09-11T14:48:10.357 に答える
2

Cursor関数に提供されるの数によって異なります。

2 つのアプローチ間のほとんどの比較では、StringBuilder4 ~ 10 個の文字列を連結する場合、文字列連結よりも優先されるようです。StringBuilder明確な理由がなければ、私はおそらく好むでしょう(たとえば、私の問題/アプリケーションに対する 2 つのアプローチのパフォーマンス比較)。StringBuilder(多くの)再割り当てを避けるために、バッファを事前に割り当てることを検討します。

文字列連結と文字列ビルダーを参照してください。この件に関するいくつかの議論については、パフォーマンスStringBuilders と Strings との連結。

于 2012-09-11T16:47:00.150 に答える
1

何回連結していますか?多数の場合は、StringBuilder を使用します。数が少ない場合は、StringBuilder を作成するオーバーヘッドが利点を上回ります。

于 2012-09-11T14:43:44.713 に答える
1

私は自分のお金を入れます

           StringBuilder sb = new StringBuilder();
           bool first = true;
           foreach (Cursor c in cursors)
           {
                if (first)
                {
                   first = false;  // only assign it once
                }
                else
                {
                    sb.Append('|');
                }
                sb.Append(Escape(c.Key) + ',' + c.Id);
            }
            return sb.ToString();

しかし、私は自分のお金と dfowler からの最新情報を入れます。彼の答えのリンクをチェックしてください。

于 2012-09-11T15:46:47.590 に答える