如何加快一个非常微不足道的功能?

LaB*_*cca 1 delphi profiling delphi-xe2

通过分析(使用ProDelphi分析器)我的应用程序,我发现如果此功能更快,我可以实现更好的性能:

function BooleanToYN(isTrue: Boolean): string;
begin
  if isTrue then
    Result := 'Y'
  else
    Result := 'N';
end;
Run Code Online (Sandbox Code Playgroud)

当我看到这段代码时,我认为它已经"优化"了.在你看来,这是加速它的方法吗?还有其他评论吗?这是遗留代码,我没有写,所以不要问我为什么会这样.当然我可以考虑改变应用程序的编写方式,无论如何,如果有办法加快这个简单的功能(可能是使用另一个现成的Delphi函数)它会很棒.

Dav*_*nan 9

您的探查器很可能无法向您提供可靠的信息.这个功能是你程序的瓶颈,这简直难以置信.

您改进该功能的主要选择是:

  1. 内联函数.
  2. 删除分支.

你会像这样实现选项2:

function BooleanToYN(isTrue: Boolean): string;
const
  BoolStr: array [Boolean] of string = ('N', 'Y');
begin
  Result := BoolStr[isTrue];
end;
Run Code Online (Sandbox Code Playgroud)

当然,将函数内联起来是很有意义的.换句话说,应用上面的两个选项.

但如果这对你的程序的性能产生任何明显的差异,那将是惊人的.想一想.您的程序是否真的花费了很大一部分运行时执行该功能?真?

分析非常困难,您应该期望分析者提供错误的信息.使用分析器时,您应该以潜在的不信任程度运行.始终最初对其输出持怀疑态度.

  • 或者跳过该函数并仅使用常量声明. (5认同)

Chr*_*ton 6

我有一个理论认为Char会比String快,但有时你只需要尝试它......

它可以通过返回CHAR而不是String来改进16倍.我希望它与字符串的分配有关.

我将原始代码放入DUnit测试框架并添加了一个测试,以循环运行它1亿次.我把它叫做YNSLoop(S代表字符串),然后再做一个名为YNCLoop(C代表Char),它返回Char而不是String,然后我根据David的代码用Array做了另一个,然后我调用了YNALoop(A代表数组).
然后根据David的建议我制作了原版的内联版本.这很好,所以我也制作了Inlined Char版本.嘿,Char版本的内联版本甚至更快.

YNSLoop:      4487 ms  (Original)
YNSILoop:     1226 ms  (Original, Inlined)
YNCLoop:       266 ms  (Char instead of String)
YNCILoop:      124 ms  (Char Inlined)
YNALoop:      4548 ms  (Array)
Run Code Online (Sandbox Code Playgroud)

结论:如果你可以使用Char代替String,那就去做吧.无论哪种方式,如果可以,请内联它.

代码如下:

function BooleanToYNSI(isTrue: Boolean): string;     inline;
begin
  if isTrue then
    Result := 'Y'
  else
    Result := 'N';
end;

function BooleanToYNS(isTrue: Boolean): string;
begin
  if isTrue then
    Result := 'Y'
  else
    Result := 'N';
end;

function BooleanToYNC(isTrue: Boolean): Char;
begin
  if isTrue then
    Result := 'Y'
  else
    Result := 'N';
end;

function BooleanToYNCI(isTrue: Boolean): Char;      inline;
begin
  if isTrue then
    Result := 'Y'
  else
    Result := 'N';
end;

function BooleanToYNArray(isTrue: Boolean): string;
const
  BoolStr: array [Boolean] of string = ('N', 'Y');
begin
  Result := BoolStr[isTrue];
end;

procedure TDBISAM_PERFTest.YNSLoop;
var
i : integer;
begin
  for i := 1 to 100000000 do
    if BooleanToYNS(True) <> 'Y' then
      Fail('Failed');
end;

procedure TDBISAM_PERFTest.YNSILoop;
var
i : integer;
begin
  for i := 1 to 100000000 do
    if BooleanToYNSI(True) <> 'Y' then
      Fail('Failed');
end;

procedure TDBISAM_PERFTest.YNCLoop;
var
i : integer;
begin
  for i := 1 to 100000000 do
    if BooleanToYNC(True) <> 'Y' then
      Fail('Failed');
end;

procedure TDBISAM_PERFTest.YNCILoop;
var
i : integer;
begin
  for i := 1 to 100000000 do
    if BooleanToYNCI(True) <> 'Y' then
      Fail('Failed');
end;

procedure TDBISAM_PERFTest.YNALoop;
var
i : integer;
begin
  for i := 1 to 100000000 do
    if BooleanToYNArray(True) <> 'Y' then
      Fail('Failed');
end;
Run Code Online (Sandbox Code Playgroud)

  • 我认为你的测试应该是:`var s:string;`然后在循环中`s:= BooleanToWhatEver`; (3认同)
  • 你的基准是有缺陷的.在调用站点,在实际程序中,调用者必须将此函数放入字符串的上下文中.因此会转换为字符串,因此会进行堆分配.因此,您必须确保您的代码复制了该代码.优化不是瓶颈的功能也是一种愚蠢的做法. (2认同)