【问题标题】:Delphi; performance of passing const strings versus passing var strings德尔福;传递 const 字符串与传递 var 字符串的性能
【发布时间】:2009-12-23 07:27:32
【问题描述】:

快速的;我是否认为将字符串传递给“作为 CONST”的方法比将字符串作为“VAR”传递的开销更多?编译器会让Delphi制作一个字符串的副本然后传递副本,如果字符串参数被声明为一个CONST,对吧?

这个问题的原因有点乏味;我们有一个遗留的 Delphi 5 实用程序,它的日子已经数不胜数了(替代品正在开发中)。它进行了大量的字符串处理,经常在各种函数和过程之间传递 1-2Kb 的字符串。在整个代码中,一直坚持使用 CONST 或 VAR 传递参数(取决于手头的工作)的“正确”观察。我们只是在寻找一些“快速获胜”,可以将执行时间缩短几微秒,让我们渡过难关,直到新版本准备好。我们考虑将内存管理器从默认的 Delphi 5 更改为 FastMM,并且我们还想知道是否值得更改字符串的传递方式 - 因为代码在字符串作为 const 传递时工作正常,我们不如果我们将这些声明更改为 var,就会发现问题 - 该方法中的代码不会更改字符串。

但实际上真的会有什么不同吗? (该程序实际上只是对这些 1kb+ish 字符串进行了大量处理;高峰时间每分钟几百个字符串)。在重写时,这些字符串被保存在对象/类变量中,因此它们并没有真正以相同的方式被复制/传递,但在遗留代码中它非常“老派”帕斯卡。

当然,我们会分析程序的整体运行情况,看看我们有什么不同,但如果我们在第一个实例中字符串传递的工作方式绝对错误,那么实际尝试这个是没有意义的!

【问题讨论】:

标签: delphi string


【解决方案1】:

不,在您的情况下使用 constvar 之间不应该有任何性能差异。在这两种情况下,指向字符串的指针都作为参数传递。如果参数是const,编译器就不允许对其进行任何修改。请注意,如果您遇到棘手的问题,这并不排除对字符串的修改:

procedure TForm1.Button1Click(Sender: TObject);
var
  s: string;
begin
  s := 'foo bar baz';
  UniqueString(s);
  SetConstCaption(s);
  Caption := s;
end;

procedure TForm1.SetConstCaption(const AValue: string);
var
  P: PChar;
begin
  P := PChar(AValue);
  P[3] := '?';
  Caption := AValue;
end;

这实际上会改变调用方法中的本地字符串变量,证明只传递了一个指向它的指针。

但一定要使用 FastMM4,它应该会产生更大的性能影响。

【讨论】:

  • 太棒了,谢谢mghie。所以我对 const/var 如何处理字符串是错误的。尴尬,但很高兴我现在知道了。我们已经在使用 HyperString 进行一些字符串操作,我想我们会将 FastMM4 放在那里,看看它会给我们带来什么。干杯!
  • var 字符串参数实际上传递了一个指向字符串变量的指针,而 const 字符串参数只是传递了字符串值。 Var因此有一个额外的间接层,所以它应该比const慢。
  • ??这对我来说没有意义。我一直认为(长)字符串总是通过引用(指针)传递。如果标记为 constvar 则它是指向传递的字符串的指针,如果未标记 either const or var,如果例程修改了字符串参数并且指针指向副本,则进行副本以避免副作用。我希望 var 字符串参数仅比 const 慢一点的唯一原因是 var 字符串参数可能具有引用计数为调用生成的编译指示对于 const 字符串参数不是必需的。
【解决方案2】:

const 用于 Delphi 中的参数基本上意味着“我不会改变它,我也不关心这是通过值传递还是通过引用传递 - 以最有效的为准我很好”。粗体部分很重要,因为它实际上是可观察的。考虑这段代码:

type TFoo =
  record
    x: integer;
    //dummy: array[1..10] of integer;
  end;

procedure Foo(var x1: TFoo; const x2: TFoo);
begin
  WriteLn(x1.x);
  WriteLn(x2.x);

  Inc(x1.x);
  WriteLn;

  WriteLn(x1.x);
  WriteLn(x2.x);
end;

var
  x: TFoo;
begin
  Foo(x, x);
  ReadLn;
end.

这里的技巧是我们将相同的变量传递给varconst,这样我们的函数就可以通过一个参数进行变异,看看这是否会影响另一个。如果你用上面的代码试试,你会看到在Foo 内增加x1.x 不会改变x2.x,所以x2 是按值传递的。但是尝试取消注释TFoo 中的数组声明,使其大小变大,然后再次运行它 - 你会看到x2.x 现在如何别名x1.x,所以我们有x2 的引用传递现在!

总而言之,const 始终是传递任何类型参数的最有效方式,但您不应该对是否拥有调用者传递的值的副本或引用做任何假设到某些(可能被您可能调用的其他代码突变)位置。

【讨论】:

    【解决方案3】:

    这确实是一个评论,但很长,所以请多多包涵。

    关于“所谓的”字符串按值传递

    Delphi总是通过引用传递stringansistring(不包括WideStrings 和ShortStrings),作为指针。
    所以字符串永远不会按值传递。
    这可以通过传递 100MB 字符串来轻松测试。

    只要你不在被调用例程的主体内更改它们,字符串传递需要 O(1) 时间(并且有一个小常数)

    然而,当传递一个没有varconst 子句的字符串时,Delphi 会做三件事。

    1. 增加字符串的引用计数。
    2. 在过程周围放置一个隐式 try-finally 块,这样当方法退出时,字符串参数的引用计数会再次减少。
    3. 当字符串被更改时(并且只有在那时),Delphi 会复制该字符串,减少传递的字符串的引用计数并在例程的其余部分使用该副本。
      它在这样做时伪造了pass by value

    关于通过引用(指针)传递

    当字符串作为constvar 传递时,Delphi 也会传递一个引用(指针),但是:

    1. 字符串的引用计数没有增加。 (微小的速度提升)
    2. 例程周围没有隐式的 try/finally,因为它不是必需的。这就是为什么const/var 字符串参数执行得更快的第 1 部分。
    3. 在例程中更改字符串时,不制作副本实际字符串已更改。对于const 参数,编译器禁止字符串交替。这是var/const 字符串参数工作速度更快的原因的第二部分。
    4. 如果 但是你需要创建一个本地变量来分配字符串; Delphi 复制字符串 :-) 并放置一个隐式 try/finally 块,消除了 const 字符串参数的 99% 以上的速度增益。

    希望这能对这个问题有所启发。
    免责声明:大部分信息来自hereherehere

    【讨论】:

      【解决方案4】:

      当使用 const afaik 时,编译器不会复制字符串。使用 const 可以节省您为所使用的字符串增加/减少 refcounter 的开销。

      通过将 memorymanager 升级到 FastMM,您将获得更大的性能提升,并且由于您经常使用字符串,因此请考虑使用 FastCode 库。

      【讨论】:

      • 谢谢,The_Fox。我们已经在使用更优化的字符串处理单元(HyperString 的一部分),从我通过快速谷歌收集的信息来看,FastCode 项目网页似乎已经关闭/消失了,而另一个主 FastCode 页面上留下的注释暗示不支持 Delphi 5。不过,我认为如果/当时机成熟,我会将 FastCode 标记为值得研究的 Delphi 7 应用程序。不过,我肯定会插入 FastMM4。谢谢!
      【解决方案5】:

      Const 已经是向函数传递参数的最有效方式。它避免了创建副本(默认,按值),甚至避免传递指针(var,按引用)。
      对于字符串来说尤其如此,并且在计算能力有限且不被浪费时确实是要走的路(因此有“老派”标签)。

      IMO,const 应该是默认约定,由程序员在真正需要时通过值或 var 更改它。这将更符合帕斯卡的整体安全性(如限制射中自己脚的机会)。

      我的 2 美分...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-05
        • 2018-10-10
        • 2012-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-28
        • 1970-01-01
        相关资源
        最近更新 更多