代码之家  ›  专栏  ›  技术社区  ›  Andreas Rejbrand

德尔福绩效:案例与假设

  •  21
  • Andreas Rejbrand  · 技术社区  · 16 年前

    我想可能有一些重叠与以前的SO问题,但我找不到一个德尔福具体的问题在这个主题上。

    case MyAction of
      ACTION1: {code};
      ACTION2: {code};
      ...
      ACTIONn: {code};
    end;
    

    比…快得多

    if MyAction = ACTION1 then
      // code
    else if MyAction = ACTION2 then
      // code
    ...
    else if MyAction = ACTIONn then
      // code;
    

    1. 我说的对吗?开关快得多?
    2. 在开关情况下,找到正确动作所需的时间实际上与n无关,对吗?也就是说,检查100万个病例的时间真的不比检查10个病例的时间长吗?
    3. 这到底是怎么回事?
    4 回复  |  直到 16 年前
        1
  •  15
  •   Community Mohan Dere    8 年前
    1. 是,开关是O(1),而级联if是O(n)
    2. 是,见(1)
    3. branch table
        2
  •  20
  •   Barry Kelly    16 年前

    编译器将case语句转换为以下语句之一:

    1. 间接跳转表
    2. 连续跳跃
    3. 二进制搜索-这是递归的,所以二进制搜索的叶子可以使用2、3或4中的任何一个。

    它使用启发式方法,例如案例数量、案例范围、不同备选方案的数量(每个备选方案可能实现一系列不同的值)等。

    O(1)

        3
  •  19
  •   gabr    16 年前

    先看看现实总是好的。。。

    var
      c: (aaa, bbb, ccc);
    
    begin
      case c of
        aaa: sleep(0);
        bbb: sleep(0);
        ccc: sleep(0);
      end;
    end.
    

    编译器将生成以下代码:

    Project56.dpr.24: case c of
    0040A1C4 0FB6053C0E4100   movzx eax,[$00410e3c]
    0040A1CB 2C01             sub al,$01
    0040A1CD 7208             jb $0040a1d7
    0040A1CF 740F             jz $0040a1e0
    0040A1D1 FEC8             dec al
    0040A1D3 7414             jz $0040a1e9
    0040A1D5 EB19             jmp $0040a1f0
    Project56.dpr.25: aaa: sleep(0);
    0040A1D7 6A00             push $00
    0040A1D9 E86EDAFFFF       call Sleep
    0040A1DE EB10             jmp $0040a1f0
    Project56.dpr.26: bbb: sleep(0);
    0040A1E0 6A00             push $00
    0040A1E2 E865DAFFFF       call Sleep
    0040A1E7 EB07             jmp $0040a1f0
    Project56.dpr.27: ccc: sleep(0);
    0040A1E9 6A00             push $00
    0040A1EB E85CDAFFFF       call Sleep
    

    更复杂的情况将被编译成测试和跳转系列。例如。。。

    var
      c: (aaa, bbb, ccc, eee, fff, ggg, hhh);
    
    begin
      case c of
        aaa: sleep(0);
        bbb: sleep(0);
        ccc: sleep(0);
        hhh: sleep(0);
      end;
    end.
    

    Project56.dpr.24: case c of
    0040A1C4 0FB6053C0E4100   movzx eax,[$00410e3c]
    0040A1CB 2C01             sub al,$01
    0040A1CD 720C             jb $0040a1db
    0040A1CF 7413             jz $0040a1e4
    0040A1D1 FEC8             dec al
    0040A1D3 7418             jz $0040a1ed
    0040A1D5 2C04             sub al,$04
    0040A1D7 741D             jz $0040a1f6
    0040A1D9 EB22             jmp $0040a1fd
    Project56.dpr.25: aaa: sleep(0);
    0040A1DB 6A00             push $00
    0040A1DD E86ADAFFFF       call Sleep
    0040A1E2 EB19             jmp $0040a1fd
    Project56.dpr.26: bbb: sleep(0);
    0040A1E4 6A00             push $00
    0040A1E6 E861DAFFFF       call Sleep
    0040A1EB EB10             jmp $0040a1fd
    Project56.dpr.27: ccc: sleep(0);
    0040A1ED 6A00             push $00
    0040A1EF E858DAFFFF       call Sleep
    0040A1F4 EB07             jmp $0040a1fd
    Project56.dpr.28: hhh: sleep(0);
    0040A1F6 6A00             push $00
    0040A1F8 E84FDAFFFF       call Sleep
    

    这类代码最可能的原因是跳转表不能很好地处理一级缓存,而且如果没有大量的case标签,测试和跳转版本可能会更快。

    这个推理的“证明”是下面的程序 翻译成跳转表。

    var
      b: byte;
    
    begin
      case b of
        0: sleep(0);
        1: sleep(0);
        2: sleep(0);
        3: sleep(0);
        4: sleep(0);
        5: sleep(0);
        6: sleep(0);
        7: sleep(0);
        8: sleep(0);
        9: sleep(0);
       10: sleep(0);
       11: sleep(0);
       12: sleep(0);
       13: sleep(0);
       14: sleep(0);
       15: sleep(0);
       16: sleep(0);
       17: sleep(0);
       18: sleep(0);
       19: sleep(0);
       20: sleep(0);
      end;
    end.
    
    Project56.dpr.12: case b of
    0040A178 0FB6C0           movzx eax,al
    0040A17B 83F814           cmp eax,$14
    0040A17E 0F8728010000     jnbe $0040a2ac
    0040A184 FF24858BA14000   jmp dword ptr [eax*4+$40a18b]
    ...
    Project56.dpr.14: 1: sleep(0);
    0040A1EB 6A00             push $00
    0040A1ED E85ADAFFFF       call Sleep
    0040A1F2 E9B5000000       jmp $0040a2ac
    Project56.dpr.15: 2: sleep(0);
    0040A1F7 6A00             push $00
    0040A1F9 E84EDAFFFF       call Sleep
    0040A1FE E9A9000000       jmp $0040a2ac
    Project56.dpr.16: 3: sleep(0);
    0040A203 6A00             push $00
    0040A205 E842DAFFFF       call Sleep
    0040A20A E99D000000       jmp $0040a2ac
    ...
    

    巴里可以对那个问题给我们一个明确的答案。我只是在测试和闲聊。

        4
  •  3
  •   Chris Thornton    16 年前