C++は最速!!と思い込んでいました。ネットで「Cのべた書きとSTLはどっちが速い」なんて、C++速いぞって記事をたまに見かけるでしょう。
しかし実際にfstreamを使ったファイルコピーを書いてみたら、C++、意外に遅いか?という結果に・・・。具体的にどれぐらい違うのかC標準ライブラリとの実行速度の比較を行なってみました。
環境
使用したのはVisualStudio 2008。VS2013でもあまり変わらないみたいです。
コード
比較したコードは下記の4つ。いづれも入力ファイルから出力ファイルへバイナリコピーします。エラー処理は省いています。
1:streambuf_iteratorとcopy()を使う
void CopyFile( const char *from_file_name, const char *to_file_name )
{
ifstream is( from_file_name, ios::in | ios::binary );
ofstream os( to_file_name, ios::out | ios::binary );
// ファイルコピー
istreambuf_iterator<char> iit(is);
istreambuf_iterator<char> end;
ostreambuf_iterator<char> oit(os);
copy( iit, end, oit );
}
2:fstream::rdbuf()と<<を使う
void CopyFile( const char *from_file_name, const char *to_file_name )
{
ifstream is( from_file_name, ios::in | ios::binary );
ofstream os( to_file_name, ios::out | ios::binary );
// ファイルコピー
os << is.rdbuf();
}
3:fstreamとバッファ(1MB)を使う
void CopyFile( const char *from_file_name, const char *to_file_name )
{
ifstream is( from_file_name, ios::in | ios::binary );
ofstream os( to_file_name, ios::out | ios::binary );
// バッファ確保
vector<char> buffer( 1024*1024 );
// ファイルコピー
while( !is.eof() )
{
size_t size = is.read( &buffer[0], buffer.size() ).gcount();
os.write( &buffer[0], size );
}
}
4:Cの標準ライブラリとバッファ(1MB)を使う
void CopyFile( const char *from_file_name, const char *to_file_name )
{
FILE *fpr = fopen( from_file_name, "rb" );
FILE *fpw = fopen( to_file_name , "wb" );
// バッファ確保
vector<char> buffer( 1024*1024 );
// ファイルコピー
while( !feof( fpr ) )
{
size_t size = fread( &buffer[0], 1, buffer.size(), fpr );
fwrite( &buffer[0], 1, size, fpw );
}
fclose( fpr );
fclose( fpw );
}
結果
Cの標準ライブラリが数倍速いです。
コード | 処理時間・キャッシュなし (ms) | 処理時間・キャッシュあり(ms) |
---|---|---|
1:streambuf_iteratorとcopy() | 2,400 | 2.000 |
2:fstream::rdbuf()と<< | 2,000 | 1,900 |
3:fstreamとバッファ | 1,200 | 500 |
4:Cの標準ライブラリ | 650 | 90 |
「キャッシュなし」はファイルのメモリへの初回読み込み、「キャッシュあり」は2回目以降の読み込みです。「キャッシュあり」はあまり意味がないと思ったのですが、速度差が大きいので載っけておきました。
キャッシュなしで比較すると、1or2(fstream+algorithm)と3(fstream)の速度比がおおざっぱに2倍、3(fstream)と4(Cライブラリ)の速度比も2倍ですから、fstream遅いわ、copy()
,<<
等のアルゴリズム遅いわで、両者の共犯でこの速度差になっていると推測できます。
(測定条件)130Mバイトのファイルを使用。x86。普通のリリースモード(速度最適化)。処理時間は多少ばらつくので数回実行して目分量で丸めています。
まとめ
CとC++(fstream)で数倍の差が出たのはちょっと驚きでした。
速度を求めるときfstreamは使用できませんね。
番外:C#
C#でも同様のコードを書いて試してみました。
private static void CopyFile( string from, string to )
{
using( BinaryReader br = new BinaryReader( File.OpenRead( from ) ) )
using( BinaryWriter bw = new BinaryWriter( File.OpenWrite( to ) ) )
{
// ファイルコピー
while(true)
{
byte[] buf = br.ReadBytes( 1024*1024 );
if( buf.Length == 0 )
break;
bw.Write( buf );
}
}
}
コード | 処理時間・キャッシュなし(ms) | 処理時間・キャッシュあり(ms) |
---|---|---|
C# | 650 | 130 |
速い。Cライブラリに肉薄。 |