1

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

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

当我看到这段代码时,我认为它已经“优化”了。您认为有没有办法加快速度?还有什么意见吗?这是遗留代码,不是我写的,所以不要问我为什么会这样。当然,我可以考虑改变应用程序的编写方式,无论如何,如果有办法加快这个简单的功能(可能使用另一个现成的 Delphi 功能),那就太好了。

4

2 回答 2

9

您的分析器很可能不会为您提供可靠的信息。这个函数是你程序的瓶颈简直难以置信。

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

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

您将像这样实现选项 2:

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

当然,使函数内联是很有意义的。换句话说,应用我上面的两个选项。

但是,如果这对您的程序的性能有任何明显的影响,那将是令人震惊的。想一想。您的程序是否真的花费了很大一部分运行时间来执行该功能?真的吗?

分析非常困难,您应该期望分析器提供错误信息。使用分析器时,您应该在不信任的基础上进行操作。最初总是对其输出持怀疑态度。

于 2013-10-14T13:35:07.053 回答
6

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

通过返回 CHAR 而不是 String,它可以提高 16 倍。我希望它与字符串的分配有关。

我将原始代码放入 DUnit 测试框架中,并添加了一个测试以将其循环运行 1 亿次。我将它称为 YNSLoop(S 表示字符串),然后制作了另一个称为 YNCLoop(C 表示 Char),它返回 Char 而不是 String,然后我根据 David 的代码用数组制作了另一个,我称之为 YNALoop(A 表示数组)。
然后,根据大卫的建议,我制作了原始版本的内联版本。那很好,所以我也做了一个内联字符版本。嘿,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)

结论:如果你可以使用 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;
于 2013-10-14T14:15:41.740 回答