长度有多快?

WeG*_*ars 3 delphi delphi-xe

我需要s在程序中经常读取字符串的长度.我设置了s一次字符串,所以我可以在变量(NoOfChars)中记住它的大小,如下所示:

type
  MyClass= class
    Public
     s: string;
     NoOfchars: integer;  
  end;

procedure MyClass.SetS(const MyString: String); 
begin
  s:= MyString;
  NoOfchars := Length(s); // <-- store it once, read it often
end;
Run Code Online (Sandbox Code Playgroud)

我想我读到的地方Length(s)和读取常量一样快,因为它只访问存储在字符串前面"hidden"字段中的字符串的长度.这很有意义,但由于我们没有源代码,我们只能猜测.也许还有其他涉及的计算?

那么,我应该使用Length(s)还是应该记住变量中的长度?

Dav*_*nan 8

你有源代码.它在System单元中.

function _UStrLen(const S: UnicodeString): Integer;
begin
  Result := Longint(S);
  if Result <> 0 then                // PStrRec should be used here, but
    Result := PLongint(Result - 4)^; // a private symbol can't be inlined
end;
Run Code Online (Sandbox Code Playgroud)

这个辅助函数被标记为内联,实际上编译器会内联它.这个程序:

{$APPTYPE CONSOLE}

var
  i: Integer;
  s: string;

begin
  i := Length(s);
  Writeln(i);
end.
Run Code Online (Sandbox Code Playgroud)

编译如下:

....
Project1.dpr.10: i := Length(s);
004060E3 A19CAB4000       mov eax,[$0040ab9c]   // $0040ab9c holds the variable s
004060E8 85C0             test eax,eax          // test for nil
004060EA 7405             jz $004060f1          
004060EC 83E804           sub eax,$04           // offset to length
004060EF 8B00             mov eax,[eax]         // read length into eax
004060F1 8BD8             mov ebx,eax           // compiler optimises i into ebx
....

代码非常简单.检查字符串变量是否为nil.如果是这样,答案就是零.否则,从字符串的适当偏移量读取长度.

这当然是一个非常快速的功能.但是,调用它的速度并不快Length,因为它是从本地变量读取的.实际上,编译器可以很好地将局部变量优化为寄存器.

因此,如果性能很重要,读入局部变量可以提高性能.但是,您必须计算现实世界的代码,以了解性能差异是否真正重要.

我个人倾向于将字符串长度存储在局部变量中,因为我需要不止一次地引用长度.如果我每次调用函数时都知道值相同,则可以通过将值存储在本地来表达.

  • `_DynArrayLength`或`__StringLength`但编译器内联asm. (2认同)

Ste*_*nke 7

FWIW您可以通过简单的测试轻松地了解变量的使用速度.当然,这并不会测试您的生产代码中的所有情况和可能性,但您会得到一个粗略的估计.

program Project1;

{$APPTYPE CONSOLE}

uses
  Diagnostics;

var
  sw: TStopwatch;
  s: string;
  len, i, x: Integer;
begin
  s := 'somestring';
  len := Length(s);
  sw := TStopwatch.StartNew;
  for i := 0 to MaxInt do
  begin
    x := len;
    if x = 0 then
  end;
  Writeln('using variable: ', sw.ElapsedMilliseconds);

  sw := TStopwatch.StartNew;
  for i := 0 to MaxInt do
  begin
    x := Length(s);
    if x = 0 then
  end;
    Writeln('using Length(s): ', sw.ElapsedMilliseconds);
  Readln;
end.
Run Code Online (Sandbox Code Playgroud)

在VM中,我得到这样的数字(发布配置):

using variable: 587
using Length(s): 1255
Run Code Online (Sandbox Code Playgroud)

  • 我累了和你争吵.数字只是显示,是使用变量更快,期间.我相信一些聪明的人可以提出一些特殊的代码,表明使用Length更快但我确信这将是一些非常假设的代码.我还认为在实际情况下使用Length的开销可能微不足道,但正如您已经写过的那样,只有分析可能会显示出来. (7认同)