gpt4 book ai didi

delphi - `const` 的使用是教条性的还是理性的?

转载 作者:行者123 更新时间:2023-12-03 14:34:06 26 4
gpt4 key购买 nike

在 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 可以显着提高速度(我曾经得到一个使用 >只需在正确的位置添加 const,分析运行中总运行时间的 10% 即可降至 <2%)。

此外,引用计数所花费的时间远不止一个周期,因为出于线程安全原因,它必须使用锁前缀来执行,因此我们谈论的更像是 50-100 个周期。如果同一缓存行中的某些内容已被中间的另一个核心修改,则更多。

至于无法测量:

program Project;

{$APPTYPE CONSOLE}

uses
Windows,
SysUtils,
Math;

function GetThreadTime: Int64;
var
CreationTime, ExitTime, KernelTime, UserTime: TFileTime;
begin
GetThreadTimes(GetCurrentThread, CreationTime, ExitTime, KernelTime, 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,
SysUtils,
Classes,
Math;

function GetThreadTime: Int64;
var
CreationTime, ExitTime, KernelTime, UserTime: TFileTime;
begin
GetThreadTimes(GetCurrentThread, CreationTime, ExitTime, KernelTime, 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, THREAD_PRIORITY_HIGHEST);

InterlockedIncrement(ActiveCount);
WaitForSingleObject(StartEvent, 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: ', 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.

在 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.

对于非线程情况。

关于delphi - `const` 的使用是教条性的还是理性的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5844904/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com