Why is CharInSet faster than Case statement?

后端 未结 5 987
借酒劲吻你
借酒劲吻你 2020-12-05 11:26

I\'m perplexed. At CodeRage today, Marco Cantu said that CharInSet was slow and I should try a Case statement instead. I did so in my parser and then checked with AQTime wha

5条回答
  •  隐瞒了意图╮
    2020-12-05 11:53

    AQTime is an instrumenting profiler. Instrumenting profilers often aren't suitable for measuring code time, particularly in microbenchmarks like yours, because the cost of the instrumentation often outweighs the cost of the thing being measured. Instrumenting profilers, on the other hand, excel at profiling memory and other resource usage.

    Sampling profilers, which periodically check the location of the CPU, are usually better for measuring code time.

    In any case, here's another microbenchmark which indeed shows that a case statement is faster than CharInSet. However, note that the set check can still be used with a typecast to eliminate the truncation warning (actually this is the only reason that CharInSet exists):

    {$apptype console}
    
    uses Windows, SysUtils;
    
    const
      SampleString = 'foo bar baz blah de;blah de blah.';
    
    procedure P1;
    var
      cp: PChar;
    begin
      cp := PChar(SampleString);
      while not CharInSet(cp^, [#0, ';', '.']) do
        Inc(cp);
    end;
    
    procedure P2;
    var
      cp: PChar;
    begin
      cp := PChar(SampleString);
      while True do
        case cp^ of
          '.', #0, ';':
            Break;
        else
          Inc(cp);
        end;
    end;
    
    procedure P3;
    var
      cp: PChar;
    begin
      cp := PChar(SampleString);
      while not (AnsiChar(cp^) in [#0, ';', '.']) do
        Inc(cp);
    end;
    
    procedure Time(const Title: string; Proc: TProc);
    var
      i: Integer;
      start, finish, freq: Int64;
    begin
      QueryPerformanceCounter(start);
      for i := 1 to 1000000 do
        Proc;
      QueryPerformanceCounter(finish);
      QueryPerformanceFrequency(freq);
      Writeln(Format('%20s: %.3f seconds', [Title, (finish - start) / freq]));
    end;
    
    begin
      Time('CharInSet', P1);
      Time('case stmt', P2);
      Time('set test', P3);
    end.
    

    Its output on my laptop here is:

    CharInSet: 0.261 seconds
    case stmt: 0.077 seconds
     set test: 0.060 seconds
    

提交回复
热议问题