mmapの方がはるかに高速です。あなたはそれをあなた自身に証明するために簡単なベンチマークを書くかもしれません:
char data[0x1000];
std::ifstream in("file.bin");
while (in)
{
in.read(data, 0x1000);
// do something with data
}
対:
const int file_size=something;
const int page_size=0x1000;
int off=0;
void *data;
int fd = open("filename.bin", O_RDONLY);
while (off < file_size)
{
data = mmap(NULL, page_size, PROT_READ, 0, fd, off);
// do stuff with data
munmap(data, page_size);
off += page_size;
}
明らかに、詳細(たとえば、ファイルが倍数でない場合にファイルの終わりに到達したときを判断する方法など)は省略していますpage_size
が、実際にはこれよりもはるかに複雑であってはなりません。 。
可能であれば、データを複数のファイルに分割して、一部ではなく全体をmmap()することができます(はるかに簡単です)。
数か月前、boost_iostreams用のスライディングウィンドウmmap()-edストリームクラスの実装が中途半端でしたが、誰も気にせず、他のもので忙しくなりました。最も残念なことに、私は数週間前に古い未完成のプロジェクトのアーカイブを削除しました、そしてそれは犠牲者の1人でした:-(
更新:Microsoftは、最初にmmapで行うことのほとんどを実行する気の利いたファイルキャッシュを実装したため、このベンチマークはWindowsではまったく異なるように見えるという警告も追加する必要があります。つまり、頻繁にアクセスされるファイルの場合は、std :: ifstream.read()を実行するだけで、ファイルキャッシュがすでにメモリマッピングを実行していて、透過的であるため、mmapと同じくらい高速になります。
最終更新mmap
:見てください、人々:OSと標準ライブラリ、ディスクとメモリ階層の多くの異なるプラットフォームの組み合わせにわたって、ブラックボックスとして表示されるシステムコールが常に常に大幅に高速になるとは言えませんよりread
。たとえ私の言葉がそのように解釈されたとしても、それは私の意図ではありませんでした。 最終的に、私のポイントは、メモリマップドI/Oは一般的にバイトベースのI/Oよりも高速であるということでした。これはまだ真実です。実験的に2つの間に違いがないことがわかった場合、私にとって合理的と思われる唯一の説明は、プラットフォームが、呼び出しのパフォーマンスに有利な方法でメモリマッピングを内部で実装していることです。read
。ポータブルな方法でメモリマップドI/Oを使用していることを完全に確認する唯一の方法は、を使用することmmap
です。移植性を気にせず、ターゲットプラットフォームの特定の特性に依存できる場合は、read
パフォーマンスをある程度犠牲にすることなく、を使用するのが適切な場合があります。
編集して回答リストをクリーンアップします:
@jbl:
スライディングウィンドウのmmapは面白そうですね。それについてもう少し言えますか?
確かに-私はGit用のC++ライブラリ(必要に応じてlibgit ++)を作成していましたが、これと同様の問題が発生しました。大きな(非常に大きな)ファイルを開くことができ、パフォーマンスが完全に向上しないようにする必要がありました。 (と同じようにstd::fstream
)。
Boost::Iostreams
すでにmapped_fileSourceがありますが、問題はmmap
ファイル全体にpingを実行していたため、2 ^(wordsize)に制限されていました。32ビットマシンでは、4GBでは十分ではありません。Gitにそれよりもはるかに大きくなるファイルがあることを期待するのは不合理ではない.pack
ので、通常のファイルI/Oに頼らずにファイルをチャンクで読み取る必要がありました。のカバーの下で、とBoost::Iostreams
の間の相互作用の多かれ少なかれ別のビューであるソースを実装しました。に継承するだけで、同様のアプローチを試すこともできます。同様に、に継承します。正しく理解するのが難しいのは、2つの間の相互作用です。 std::streambuf
std::istream
std::filebuf
mapped_filebuf
std::fstream
a mapped_fstream
Boost::Iostreams
いくつかの作業が行われ、フィルターとチェーンのフックも提供されるので、そのように実装する方が便利だと思いました。