代码之家  ›  专栏  ›  技术社区  ›  robsoft

传递常量字符串与传递var字符串的性能

  •  10
  • robsoft  · 技术社区  · 15 年前

    快速一点;我是否认为将字符串传递给方法“as a const”比将字符串传递为“var”需要更多的开销?如果字符串参数声明为常量,编译器会让delphi复制字符串,然后传递副本,对吗?

    这个问题的原因有点乏味;我们有遗产 德尔福5 实用程序,其日期是真正的数字(替换正在开发中)。它执行大量的字符串处理,经常在各种函数和过程之间传递1-2KB字符串。在整个代码中,坚持使用const或var传递参数(取决于手头的工作)的“正确”观察。我们只是在寻找一些“快速胜利”,这可能会使执行时间缩短几微秒,以帮助我们在新版本准备就绪之前渡过难关。我们考虑将内存管理器从默认的delphi 5-one改为fastmm,我们还想知道是否值得改变字符串的传递方式——因为代码可以很好地处理作为const传递的字符串,如果我们将这些声明改为var,我们就看不到问题了——该方法中的代码不会改变。这个字符串。

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

    当然,我们将对程序的整体运行进行分析,以了解我们已经取得了什么不同,但是如果我们在第一个实例中对字符串传递的工作方式绝对错误的话,那么实际上尝试这种方法是没有意义的!

    5 回复  |  直到 14 年前
        1
  •  12
  •   mghie    15 年前

    不,使用之间不应该有任何性能差异 const var 以你为例。在这两种情况下,指向字符串的指针都作为参数传递。如果参数为 康斯特 编译器只是不允许对其进行任何修改。注意,这并不排除对字符串的修改,如果您遇到困难:

    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,它应该有更大的性能影响。

        2
  •  9
  •   Pavel Minaev    15 年前

    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.
    

    这里的技巧是我们传递相同的变量 var 作为 康斯特 ,这样我们的函数就可以通过一个参数发生变化,看看这是否影响到另一个参数。如果使用上面的代码进行尝试,您将看到 x1.x 里面 Foo 不会改变 x2.x 如此 x2 按值传递。但尝试取消对中的数组声明的注释 TFoo ,这样它的大小就变大了,并再次运行它—您将看到 x2.x 现在别名 x1.x ,所以我们已经通过参考 X2 现在!

    总而言之, 康斯特 始终是传递任何类型参数的最有效方法,但是您不应该对是否有调用方传递的值的副本,或者对某些(可能会被您调用的其他代码改变)位置的引用进行任何假设。

        3
  •  4
  •   Community CDub    8 年前

    这真是一个评论,但很长的一段让我忍无可忍。

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

    德尔菲 总是 通行证 string ansistring (不包括宽字符串和短字符串) 通过引用,作为指针。
    所以字符串永远不会按值传递。
    通过在周围传递100MB字符串,可以很容易地测试这一点。

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

    但是,当传递字符串时 var const 条款,德尔菲做三件事。

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

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

    当字符串作为 常量 var ,delphi也传递一个引用(指针),但是:

    1. 字符串的引用计数不会增加。(微小、微小的速度增加)
    2. 由于不需要,所以不会在例程中使用隐式try/finally。这是第一部分为什么 const/var 字符串参数执行速度更快。
    3. 当在例程中更改字符串时, 不复制 实际字符串已更改。为了 康斯特 参数编译器禁止字符串替换。这是原因的第2部分 var/const 字符串参数工作更快。
    4. 如果 但是,您需要创建一个本地var来将字符串分配给;delphi复制字符串:-)并放置一个隐式的try/finally块,从而消除了 常量 字符串参数。

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

        4
  •  3
  •   The_Fox    15 年前

    编译器在使用时不会复制字符串 康斯特 阿法克。使用 康斯特 为使用的字符串节省递增/递减refcounter的开销。

    通过将memoryManager升级到fastmm,您将获得更大的性能库,并且,由于您对字符串做了很多工作,因此考虑使用fastcode库。

        5
  •  2
  •   Francesca    15 年前

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

    国际海事组织, const 应该是默认的约定,由程序员在真正需要时根据值或变量来更改它。这更符合Pascal的整体安全性(如限制自己脚上开枪的机会)。

    我的2岁…