在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.
对于非螺纹的情况。