长度有多快?

时间:2014-05-10 10:42:58

标签: 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;

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

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

3 个答案:

答案 0 :(得分: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;

这个辅助函数被标记为内联,实际上编译器会内联它。这个计划:

{$APPTYPE CONSOLE}

var
  i: Integer;
  s: string;

begin
  i := Length(s);
  Writeln(i);
end.

编译为以下内容:

....
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,即使按内联方式调用它也不会那么快,因为它是从局部变量读取的。实际上,编译器可以很好地将局部变量优化为寄存器。

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

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

答案 1 :(得分: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.

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

using variable: 587
using Length(s): 1255

答案 2 :(得分:0)

当读取字符串的长度时,Delphi会读取字符串的隐藏长度字段。但是读取隐藏字段需要比读取整数更多的cpu指令。所以Length()很快,但没有读取NoOfChars字段那么快。

理论上,编译器可能能够根据上下文进一步优化读取长度。因此,我建议您在真正的单词应用程序中进行一些速度测量。