查找映射到小整数的常量时,使用case语句或常量数组会更快吗?

Dan*_*ula 10 arrays delphi performance switch-statement

例如:我将数字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;
Run Code Online (Sandbox Code Playgroud)

常数组示例:

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; 
Run Code Online (Sandbox Code Playgroud)

Dav*_*nan 11

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

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

jmp dword ptr [eax*4+$40428f]
Run Code Online (Sandbox Code Playgroud)

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

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

仅从性能上看这一点,并忽略函数中的语义差异,主要区别在于使用的版本case在输入值上有一个测试和分支,这在数组版本中是不存在的.此外,使用的版本case具有更大的代码,因此可能更少缓存友好.因此,通过对代码的分析,我们可能期望阵列版本更快.它没什么可做的,它没有分支,代码更小.

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


Arn*_*hez 9

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

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

但是AFAIR我发现当指向64位时,case指令不会在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; 
Run Code Online (Sandbox Code Playgroud)

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


And*_*and 8

两者都超级快,但我相信阵列方法会更快,如果有任何差异的话.

但是,我肯定会采用数组方法,因为它将逻辑与原始数据分开.(想象一下,你需要支持两种不同的语言 - 比较你在每种情况下的表现方式.)它也更加惯用.