C#実行速度比較

blogサーバ構築記(サーバ構築記)さんで、C#の実行速度に関するおもしろい記事を見たので、速度比較してみます。

元の記事はこちら

ファイル中の文字列をカウントするコードです。C#でポインタを使って文字列を探し出しています。これと、素直に書いたコードがどれだけ違うのか興味を覚えて、実行速度を比較してみました。実行速度はメモリ状況など様々な要因で変わるので、なんともいえないところはありますが、素直な(つもりの)コードとあまりに速度が違ったのでショックでした。

using System;
using System.IO;
using System.Text;

namespace consTest
{
  public class grepCount
  {
    public grepCount() {}

    unsafe static int TestOrginal( string filePath )
    {
      FileStream fp;
      FileInfo fInfo   = new FileInfo( filePath );
      byte[] cbuf      = new byte[ (int)fInfo.Length ];
      int count        = 0;
    
      for ( int j = 0; j < 100; j++ )
      {
        fp = new FileStream( filePath, FileMode.Open, FileAccess.Read );
        count = 0;
      
        try
        {
          fp.Read( cbuf, 0, (int)fInfo.Length );
        }
        catch ( System.ArgumentException )
        {
          System.Console.Write( "引数がおかしいです" );
          Environment.Exit( 1 );
        }
        catch ( System.Exception )
        {
          System.Console.Write( "ファイルエラー" );
          Environment.Exit( 1 );
        }
        finally 
        {
          fp.Close();
        }

        //検索
        String str = "cool";
        char[] str_cp = str.ToCharArray();
        fixed ( byte* pArray = &cbuf[0] )
        {
          int max = (int)fInfo.Length;
          for ( int k = 0; k < max; k++ )
          {
            if ( *(pArray + k) == str_cp[0] )
            {
              count++;
              for( int m = 1; m < str_cp.Length; m++ )
              {
                k++;
                if ( *(pArray + k) != str_cp[m] )
                {
                  count--;
                  break;
                }
              }
            }
          }
        }
      }
      return count;
    }

    static int TestReadLineAndIndexOf( string filePath )
    {
      string keyword = "cool";
      int count = 0;

      for ( int j = 0; j < 100; j++ )
      {
        count = 0;
        using ( StreamReader sr = new StreamReader( filePath ) )
        {
          string buff;
          while ( ( buff = sr.ReadLine() ) != null )
          {
            int pos = 0;
            while ( 0 <= ( pos = buff.IndexOf( keyword, pos ) ) )
            {
              count++;
              pos++;
            }
          }
        }
      }
      return count;
    }

    static int TestIndexOf( string filePath )
    {
      string str = "cool";
      int count = 0;

      string buff;
      using ( StreamReader sr = new StreamReader( filePath ) )
      {
        buff = sr.ReadToEnd();
      }

      for ( int j = 0; j < 100; j++ )
      {
        count = 0;
        int pos = 0;
        while ( 0 <= ( pos = buff.IndexOf( str, pos ) ) )
        {
          count++;
          pos++;
        }
      }
      return count;
    }

    [STAThread]
    static void Main( string[] args )
    {
      String filePath  = "./aaa.txt";

      const int testNum = 3;
      int[] count = new int[ testNum ];
      int[] tick  = new int[ testNum + 1 ];
      int testCount = 0;

      tick[ testCount ]  = Environment.TickCount;
      count[ testCount ] = TestOrginal( filePath );
      testCount++;

      tick[ testCount ]  = Environment.TickCount;
      count[ testCount ] = TestReadLineAndIndexOf( filePath );
      testCount++;

      tick[ testCount ]  = Environment.TickCount;
      count[ testCount ] = TestIndexOf( filePath );
      testCount++;

      tick[ testCount ]  = Environment.TickCount;

      Console.WriteLine( "TestOrginal            : {0}, {1}msec", count[ 0 ], tick[ 1 ] - tick[ 0 ] );
      Console.WriteLine( "TestReadLineAndIndexOf : {0}, {1}msec", count[ 1 ], tick[ 2 ] - tick[ 1 ] );
      Console.WriteLine( "TestIndexOf            : {0}, {1}msec", count[ 2 ], tick[ 3 ] - tick[ 2 ] );
      Console.ReadLine();
    }
  }
}

TestOrginal()がオリジナルのコード。TestReadLineAndIndexOf()が私なりの素直なコード。これがあまりに遅いので、じゃあ、ファイルを全部読んでIndexOfだけ比較したらどうなるのと思って書いたのが TestIndexOf()。
GCやファイルがメモリ中にあるかなど、速度に影響があるものは多数ありますが、何度かいろいろな状況でやってみても速度差はかなり違いました。

stringのIndexOfがどういう処理をしているのか、興味がムクムク。

(追記:転載許可をいただいたので、ソースを全部埋めました。)