我正在浏览开源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有什么不妥?
答案 0 :(得分:30)
我更改了代码,是的,它在分配数量(GetEnumerator())调用方面产生了巨大差异。想象一下,这段代码每秒数百万次。分配的调查员数量是荒谬的,可以避免。
编辑: 我们现在反转控制以避免任何分配(直接写入编写器): https://github.com/SignalR/SignalR/blob/2.0.2/src/Microsoft.AspNet.SignalR.Core/Messaging/Cursor.cs#L36
答案 1 :(得分:3)
希望改变这个的人真正衡量差异。
答案 2 :(得分:2)
这取决于为函数提供的Cursor
的数量。
两个apporaches之间的大多数比较似乎在结合4-10个字符串时优于StringBuilder
字符串连接。如果我没有明确的理由(例如 我的问题/应用 的两种方法的性能比较),我很可能会支持StringBuilder
。我会考虑在StringBuilder
中预先分配一个缓冲区以避免(很多)重新分配。
有关此主题的一些讨论,请参阅String concatenation vs String Builder. Performance和Concatenating 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的更新。查看答案中的链接。