编译器是否优化字符串拼接?

4
我在代码中有一些情况需要构建大量文本字符串,比如复杂的SQL语句。我打算将这些文本多次组合在一起,每次略有不同的参数。我已经养成了使用一个名为procedure A(const S: String);的子程序的习惯,该子程序简单地将文本(S)附加到较大的字符串上Text := Text + S + #10 + #13; 我想知道与传统的字符串连接相比,这样做是否会影响性能?我开始认为编译器会优化这样的操作:
Text := 'some' + ' ' + 'text' + ' ' + 'and' + ' ' + 'such';

to

Text := 'some text and such';

这是真的吗?编译器会优化这种情况吗?如果是这样,我可能决定将所有内容更改为类似于这样的东西:

Text := 'select something from sometable st'+#10+#13+
  'join someothertable sot on sot.id = st.sotid'+#10+#13+
  'where sot.somevalue = 1'+#10+#13+
  'order by sot.sorting';

这个理论上比...更快吗?

Text:= Text + 'select something from sometable st'+#10+#13;
Text:= Text + 'join someothertable sot on sot.id = st.sotid'+#10+#13;
Text:= Text + 'where sot.somevalue = 1'+#10+#13;
Text:= Text + 'order by sot.sorting';

或者我通常的做法是:
A('select something from sometable st');
A('join someothertable sot on sot.id = st.sotid');
A('where sot.somevalue = 1');
A('order by sot.sorting');

2
为什么不直接在调试器中打开它并查看生成的汇编代码? - Mason Wheeler
2
如果你要将那段文本作为SQL查询发送,那么数据库查询所需的时间将比创建查询字符串的代码多几个数量级。 - David Heffernan
2
只是好奇:为什么你使用 #10#13 (LF CR) 而不是 #13#10 (CR LF)? - Marjan Venema
5
使用sLineBreak,无需记住哪个是先写的。 - Sertac Akyuz
1
那个SQL查询只是一个真实场景的快速示例。在这种情况下,我想更清楚地说明这里所指的内容。请考虑Knuth的话:“程序员浪费了大量时间思考或担心程序中非关键部分的速度,而这些效率的尝试实际上在调试和维护时会产生强烈的负面影响。我们应该忘记小的低效率,大约97%的时间:过早的优化是万恶之源。然而,在关键的3%机会中,我们不应该放弃。” - RobertFrank
显示剩余5条评论
2个回答

9

像这样的表达式

'a' + 'b'

在编译时进行求值。这意味着赋值操作

str := 'a' + 'b';

产生的编译代码与以下内容相同
str := 'ab';

另一方面,针对IT技术相关内容:

但是,

str := 'a';
str := str + 'b';

连接操作是在运行时执行的。


这正是我所希望和期待的,只是需要从更有经验的人那里听到,谢谢! - Jerry Dodge
1
这是“窥孔优化”之一,名为“常量折叠”。请参见http://en.wikipedia.org/wiki/Constant_folding。Delphi编译器没有实现所有这些优化,但实现了最常见和有用的优化。好处是我从未见过Delphi优化失败代码逻辑,而有些激进的编译器在优化设置方面有时没有一致的行为。 - Arnaud Bouchez
非常好。它使得将一系列连接写成的非常长的内联字符串与Perl和Python等语言中可能的“here document”或“multiline string literal”一样高效。 - Warren P

0
请注意,当使用非常量表达式时,将所有连接放在一个表达式中仍然更有效率。考虑以下代码:
  A := '*';
  B := 'person';
  C := 'first_name=''Jerry''';

  Q := 'select ';
  Q := Q + A;
  Q := Q + ' from ';
  Q := Q + B;
  Q := Q + ' where ';
  Q := Q + C;

上述六个语句将执行5个单独的连接操作。 而:

  Q := 'select ' + A + ' from ' + B + ' where ' + C;

将执行单个连接。Delphi将为结果分配必要的空间,并将六个值中的每一个复制到该空间中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接