加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 是使用“const”教条还是理性?

发布时间:2020-12-15 10:18:30 所属栏目:大数据 来源:网络整理
导读:在Delphi中,您可以通过将参数传递为const来加快您的代码,例如 function A(const AStr: string): integer;//orfunction B(AStr: string): integer; 假设两个函数内部都有相同的代码,它们之间的速度差可以忽略不计,我怀疑它甚至可以用一个循环计数器来测量
在Delphi中,您可以通过将参数传递为const来加快您的代码,例如
function A(const AStr: string): integer;

//or

function B(AStr: string): integer;

假设两个函数内部都有相同的代码,它们之间的速度差可以忽略不计,我怀疑它甚至可以用一个循环计数器来测量,如:

function RDTSC: comp;
var
  TimeStamp: record case byte of
    1: (Whole: comp);
    2: (Lo,Hi: Longint);
  end;
begin
  asm
    db $0F; db $31;
    mov [TimeStamp.Lo],eax
    mov [TimeStamp.Hi],edx
  end;
  Result := TimeStamp.Whole;
end;

这样做的原因是功能A中的所有const都是为了防止AStr的引用计数增加。
但增量只需要我的多核CPU的一个核心的一个周期,所以…

为什么要打扰const?

解决方法

如果函数没有其他原因包含一个隐含的try / finally,并且函数本身没有太多的工作,使用const可能会导致显着的加速(我曾经有一个使用> 10%的总运行时间,只需在正确的位置添加一个const即可在剖析运行中低于<2%)。 此外,引用计数需要比一个循环多得多,因为它必须用于锁定前缀来执行线程安全的原因,所以我们说的更像是50-100个循环。更多如果同一个高速缓存行中的某些内容被另一个内核修改。 至于无法衡量它:
program Project;

{$APPTYPE CONSOLE}

uses
  Windows,SysUtils,Math;

function GetThreadTime: Int64;
var
  CreationTime,ExitTime,KernelTime,UserTime: TFileTime;
begin
  GetThreadTimes(GetCurrentThread,CreationTime,UserTime);
  Result := PInt64(@UserTime)^;
end;

function ConstLength(const s: string): Integer;
begin
  Result := Length(s);
end;

function NoConstLength(s: string): Integer;
begin
  Result := Length(s);
end;

var
  s : string;
  i : Integer;
  j : Integer;

  ConstTime,NoConstTime: Int64;

begin
  try
    // make sure we got an heap allocated string;
    s := 'abc';
    s := s + '123';

    //make sure we minimize thread context switches during the timing
    SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_TIME_CRITICAL);

    j := 0;
    ConstTime := GetThreadTime;
    for i := 0 to 100000000 do
      Inc(j,ConstLength(s));
    ConstTime := GetThreadTime - ConstTime;

    j := 0;
    NoConstTime := GetThreadTime;
    for i := 0 to 100000000 do
      Inc(j,NoConstLength(s));
    NoConstTime := GetThreadTime - NoConstTime;

    SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_NORMAL);

    WriteLn('Const: ',ConstTime);
    WriteLn('NoConst: ',NoConstTime);
    WriteLn('Const is ',(NoConstTime/ConstTime):2:2,' times faster.');
  except
    on E: Exception do
      Writeln(E.ClassName,': ',E.Message);
  end;
  if DebugHook <> 0 then
    ReadLn;
end.

在我的系统上生成此输出:

Const: 6084039
NoConst: 36192232
Const is 5.95 times faster.

编辑:如果我们添加一些线程争用,它会变得有趣:

program Project;

{$APPTYPE CONSOLE}

uses
  Windows,Classes,UserTime);
  Result := PInt64(@UserTime)^;
end;

function ConstLength(const s: string): Integer;
begin
  Result := Length(s);
end;

function NoConstLength(s: string): Integer;
begin
  Result := Length(s);
end;

function LockedAdd(var Target: Integer; Value: Integer): Integer; register;
asm
        mov     ecx,eax
        mov     eax,edx
   lock xadd    [ecx],eax
        add     eax,edx
end;

var
  x : Integer;
  s : string;

  ConstTime,NoConstTime: Integer;

  StartEvent: THandle;

  ActiveCount: Integer;
begin
  try
    // make sure we got an heap allocated string;
    s := 'abc';
    s := s + '123';

    ConstTime := 0;
    NoConstTime := 0;

    StartEvent := CreateEvent(nil,True,False,'');

    ActiveCount := 0;
    for x := 0 to 2 do
      TThread.CreateAnonymousThread(procedure
      var
        i : Integer;
        j : Integer;
        ThreadConstTime: Int64;
      begin
        //make sure we minimize thread context switches during the timing
        SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_HIGHEST);

        InterlockedIncrement(ActiveCount);
        WaitForSingleObject(StartEvent,INFINITE);
        j := 0;
        ThreadConstTime := GetThreadTime;
        for i := 0 to 100000000 do
          Inc(j,ConstLength(s));
        ThreadConstTime := GetThreadTime - ThreadConstTime;

        SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_NORMAL);

        LockedAdd(ConstTime,ThreadConstTime);
        InterlockedDecrement(ActiveCount);
      end).Start;

    while ActiveCount < 3 do
      Sleep(100);

    SetEvent(StartEvent);

    while ActiveCount > 0 do
      Sleep(100);

    WriteLn('Const: ',ConstTime);

    ResetEvent(StartEvent);

    for x := 0 to 2 do
      TThread.CreateAnonymousThread(procedure
      var
        i : Integer;
        j : Integer;
        ThreadNoConstTime: Int64;
      begin
        //make sure we minimize thread context switches during the timing
        SetThreadPriority(GetCurrentThread,INFINITE);
        j := 0;
        ThreadNoConstTime := GetThreadTime;
        for i := 0 to 100000000 do
          Inc(j,NoConstLength(s));
        ThreadNoConstTime := GetThreadTime - ThreadNoConstTime;

        SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_NORMAL);

        LockedAdd(NoConstTime,ThreadNoConstTime);
        InterlockedDecrement(ActiveCount);
      end).Start;

    while ActiveCount < 3 do
      Sleep(100);

    SetEvent(StartEvent);

    while ActiveCount > 0 do
      Sleep(100);

    WriteLn('NoConst: ',E.Message);
  end;
  if DebugHook <> 0 then
    ReadLn;
end.

在6核心机器上,这给我:

Const: 19968128
NoConst: 1313528420
Const is 65.78 times faster.

EDIT2:通过调用Pos替换对Length的调用(我选择了最坏的情况,搜索字符串中不包含的东西):

function ConstLength(const s: string): Integer;
begin
  Result := Pos('x',s);
end;

function NoConstLength(s: string): Integer;
begin
  Result := Pos('x',s);
end;

结果是:

Const: 51792332
NoConst: 1377644831
Const is 26.60 times faster.

对于螺纹外壳,以及:

Const: 15912102
NoConst: 44616286
Const is 2.80 times faster.

对于非螺纹的情况。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读