“不要在这个热代码路径中使用StringBuilder或foreach”

时间:2012-09-11 14:39:33

标签: .net optimization foreach signalr stringbuilder

我正在浏览开源SignalR项目的源代码,我看到this diff code名为“不要在此热门代码路径中使用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有什么不妥?

5 个答案:

答案 0 :(得分:30)

我更改了代码,是的,它在分配数量(GetEnumerator())调用方面产生了巨大差异。想象一下,这段代码每秒数百万次。分配的调查员数量是荒谬的,可以避免。

编辑: 我们现在反转控制以避免任何分配(直接写入编写器): https://github.com/SignalR/SignalR/blob/2.0.2/src/Microsoft.AspNet.SignalR.Core/Messaging/Cursor.cs#L36

答案 1 :(得分:3)

希望改变这个的人真正衡量差异。

  • 每次实例化一个新的stringbuilder都会有开销。 这也给内存/垃圾收集带来压力。
  • 编译器可以为简单连接生成'stringbuilderlike'代码
  • FOR可能实际上更慢,因为它可能需要边界检查而不是 完成foreach循环,因为编译器'知道'它们在界限范围内。

答案 2 :(得分:2)

这取决于为函数提供的Cursor的数量。

两个apporaches之间的大多数比较似乎在结合4-10个字符串时优于StringBuilder字符串连接。如果我没有明确的理由(例如 我的问题/应用 的两种方法的性能比较),我很可能会支持StringBuilder。我会考虑在StringBuilder中预先分配一个缓冲区以避免(很多)重新分配。

有关此主题的一些讨论,请参阅String concatenation vs String Builder. PerformanceConcatenating with StringBuilders vs. Strings

答案 3 :(得分:1)

你在做多少连接?如果很多,请使用StringBuilder。如果只是少数,那么创建StringBuilder的开销将超过任何优势。

答案 4 :(得分: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的更新。查看答案中的链接。