10

例如:我将数字 1 到 7 映射到星期几。我可以使用包含七项的 case 语句来查找它们,或者使用包含七项的常量数组。哪个更快?

案例示例:

function GetDayNameBr(Num: Integer): String;
begin
  case Num of
    1: Result := 'Domingo';
    2: Result := 'Segunda';
    3: Result := 'Terça';
    4: Result := 'Quarta';
    5: Result := 'Quinta';
    6: Result := 'Sexta';
    7: Result := 'Sábado';
  end;       
end;

常量数组示例:

function GetDayNameBr(Num: Integer): String;
const
  DayNames: array [1..7] of String = (
    'Domingo',
    'Segunda',
    'Terça',
    'Quarta',
    'Quinta',
    'Sexta',
    'Sábado');
begin
  Result := DayNames[Num];       
end; 
4

3 回答 3

11

这两个函数的性能特征不同的主要原因是它们做的事情不同。你不是在比较喜欢和喜欢。当输入值在 1 到 7 范围内时,行为是相同的。但是,当输入值超出该范围时,行为就会发散。

第一个版本,使用case,必须首先检查值是否在 1 到 7 的范围内。只有这样才允许实际分配给Result。如果值在 1 到 7 的范围内,则编译器将 case 语句转换为无条件jmp语句,如下所示:

jmp dword ptr [eax*4+$40428f]

eax是日索引。这些跳转的目标是简单地将字符串文字分配给Result变量的指令。

第二个版本使用数组,不检查输入值是否在范围内。即使输入值超出范围,它也会直接索引到数组中,当然这样的数组索引会导致未定义的行为。所以这就是行为分歧的地方。

纯粹从性能来看,忽略函数中的语义差异,主要区别在于使用的版本case对输入值进行了测试和分支,而数组版本中不存在。此外,使用的版本case代码更大,因此可能对缓存不太友好。因此,通过对代码的分析,我们可能期望数组版本更快。它要做的事更少,没有分支,代码更小。

如果性能对您来说真的很重要,那么您需要在运行此代码的实际设置中执行一些实际的计时。我无法执行这些计时,因为它们是人为的。任何时候只有在您的代码上下文中才具有真正的意义。确实很合理的是,在您的程序设置中,您将无法测量两个版本之间的差异。在这种情况下,上面的分析将毫无意义。

于 2013-06-26T15:38:58.760 回答
9

两者几乎同样快,至少在 x86 下,即使用 32 位 Delphi 编译器。

该数组将生成索引查找,而当针对 32 位时,案例将基于查找表生成跳转指令。数组会快一点,但只是稍微快一点。

但是 AFAIR 我发现当目标是64 bitcase时,该指令不会在 x64 下生成这样的查找表。它会生成一个比较和条件跳转的列表(类似于),这明显比较慢。if value=1 then ... else if value=2 then...

在您的情况下,我将使用数组查找和枚举而不是普通整数值。它将编译为整数,但更容易调试和进化。如果枚举发生变化,常量数组将不再编译,因此您将能够在编译时避免某些问题,而不是在运行时。对于这样的小列表,我尝试详尽地使用枚举,而不是整数。这是 Delphi/pascal 的一种,我在 C# 或 Java 中非常想念它。

type
  TDay = (dDomingo, dSegunda, dTerca, dQuarta, dSexta, dSabado);

function GetDayNameBr(Num: TDay): String; 
const
  DayNames: array [TDay] of String = (
    'Domingo',
    'Segunda',
    'Terça',
    'Quarta',
    'Quinta',
    'Sexta',
    'Sábado');
begin
  Result := DayNames[Num];       
end; 

或者,更好的是恕我直言,直接DayNames[Num]在代码中,这将是所有平台上最安全和最快的。

于 2013-06-26T18:14:38.013 回答
8

两者都非常快,但我相信数组方法的速度要快得多,如果有任何区别的话。

但是,我肯定会选择数组方法,因为它将逻辑与原始数据分开。(想象一下你需要支持两种不同的语言——比较你在每种情况下是如何做到的。)它也更惯用。

于 2013-06-26T14:08:12.620 回答