Wim*_*dse 21 .net c# string clr optimization
我发现常量字符串表达式的连接由编译器优化为一个字符串.
现在使用只在运行时知道的字符串串联,为什么编译器不会优化循环中的字符串连接和多于10个字符串的串联来StringBuilder.Append代替?我的意思是,这是可能的,对吧?实例化a StringBuilder并进行每个连接并将其转换为Append()呼叫.
是否有任何理由为什么这应该或可以 不进行优化?我错过了什么?
LBu*_*kin 41
明确的答案必须来自编译器设计团队.但是让我在这里捅一下......
如果你的问题是,编译器为什么不转这个:
string s = "";
for( int i = 0; i < 100; i ++ )
s = string.Concat( s, i.ToString() );
Run Code Online (Sandbox Code Playgroud)
进入这个:
StringBuilder sb = new StringBuilder();
for( int i = 0; i < 100; i++ )
sb.Append( i.ToString() );
string s = sb.ToString();
Run Code Online (Sandbox Code Playgroud)
最可能的答案是,这不是优化.这是对代码的重写,它引入了基于开发人员所具有的知识和意图的新构造 - 而不是编译器.
这种类型的更改需要编译器比适当的更多地了解BCL.如果明天会有更优化的字符串组装服务怎么办?编译器应该使用它吗?
如果您的循环条件更复杂,如果编译器尝试执行某些静态分析以确定这种重写的结果是否仍然在功能上相同,那该怎么办?在许多方面,这就像解决暂停问题.
最后,我不确定在所有情况下这都会导致代码执行速度更快.在StringBuilder附加文本时实例化和调整其内部缓冲区的大小是有成本的.事实上,追加的成本与被连接的字符串的大小,有多少,内存压力看起来很紧密相关.这些是编译器无法提前预测的内容.
编写性能良好的代码是开发人员的工作.编译器只能通过进行某些安全,不变的保留优化来提供帮助.不要为您重写代码.
Eri*_*ert 30
LBuskin的答案非常好; 我只想补充几件事.
首先,JScript.NET确实进行了这种优化.JScript经常被经验较少的程序员用于涉及在循环中构造大字符串的任务,例如构建JSON对象,HTML数据等.
由于那些程序员可能不知道天真字符串分配的n平方成本,可能不知道字符串构建器的存在,并且经常使用这种模式编写代码,我们认为将此优化放入JScript是合理的.净.
C#程序员倾向于更多地意识到他们编写的代码的底层成本,并且更多地意识到StringBuilder等现成部件的存在,因此他们需要更少的优化.而更重要的是,C#的设计理念是,它是一种"尽我所能"的语言,至少具有"魔力"; JScript是一种"尽我所能"的语言,它尽力弄清楚如何最好地为您服务,即使这意味着有时候猜错了.这两种哲学都是有效和有用的.
有时它会"走另一条路".将此选项与我们对字符串开关的选择进行比较.字符串上的开关实际上被编译为包含字符串的字典的创建,而不是作为一系列字符串比较.这种优化可能很糟糕; 简单地进行字符串比较可能会更快.但是在这里我们猜测你"意味着"转换为表查找而不是一系列"if"语句 - 如果你的意思是if语句系列,你可以自己轻松地写出来.
Jon*_*eet 16
对于多个字符串的单个串联(例如a + b + c + d + e + f + g + h + i + j),您真的想要使用String.ConcatIMO.它有为每个调用构建一个数组的开销,但它的好处是该方法可以在需要分配任何内存之前计算出结果字符串的确切长度.StringBuilder.Append(a).Append(b)...每次只提供一个值,因此构建器不知道要分配多少内存.
至于在循环中执行它 - 此时你已经添加了一个新的局部变量,并且你必须添加代码以在恰当的时间(调用StringBuilder.ToString())写回字符串变量.当你在调试器中运行时会发生什么?如果不看到价值积累,只是在循环结束时变得可见,难道不会让人感到困惑吗?哦,当然你必须执行适当的验证,在循环结束之前的任何时候都不使用该值...
两个原因:
您可以建议人们对他们的应用程序使用正确的调用,但在某些时候,开发人员有责任正确使用它.
编辑:关于截止,我们还有另外几个问题:
| 归档时间: |
|
| 查看次数: |
2339 次 |
| 最近记录: |