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がどういう処理をしているのか、興味がムクムク。
(追記:転載許可をいただいたので、ソースを全部埋めました。)