mmapのほうがreadより速いという迷信について

@ITに以下のような記事が出て、

 今回からしばらくの間は、まったく逆の例、つまり使うとプログラムの処理性能が上がるというシステムコールを紹介していく。システムコールを呼ぶ回数は少ない方が処理性能は高くなるという原則は変わらないが、呼び出しておくと処理性能が向上するシステムコールというものが存在するのだ。こうしたシステムコールを使わないでいることは、とてももったいない。

 今回紹介するシステムコールは「mmap(2)」だ。ここでは詳しく仕組みを解説しないが、mmap(2)は、プログラムの処理性能に必ず良い影響を与える。

やはりあった? 高速化に効くシステムコール (1/2):知ってトクするシステムコール(3) - @IT

それを真に受けたのか、「Go言語でmmapシステムコールを使ったファイル読み込みの高速化検討とC言語のコンパイラの話 - ryochack.blog」のようなブログエントリも上がっている。

が、「mmapだと必ず速くなる」なんて迷信ですから!!!

これらの記事で紹介されているベンチマークで read が mmap よりも遅く見えるのは、非常に大きなバッファを確保しているから。正しいコードを書けば、シーケンシャルアクセスを行うケースにおいて read(2) が mmap(2) より大幅に遅いということは、まず起こらない。むしろ、read(2) のほうが mmap(2) よりも速くなるというケースも実際には多い。

たとえば、上記のうち後者の記事の read を使うベンチマークを適切なバッファサイズを使うよう変更すると、僕の手元では read(2) を使う版(ソースコード)のほうが高速になる (MacBook Pro / Mountain Lion で計測、テストデータは32MB)。

アクセス方式 処理時間
read 0.028
mmap 0.035

Linux でも mmap(2) がシーケンシャルアクセスの場合に性能が出ないという問題が知られていたという経緯があって、ガチャピンで知られる kosaki さんが 2.6.34 で入ったパッチを紹介する記事(革命の日々! 2.6.34のused once ページに対する改善をcopybenchで検証してみた)を過去に書いたりしている(が、この記事の時点でも、まだread/writeを使った方が速い)。

まあそういうものなので、迷信です。

ついでにいうと、mmap(2) でdisk I/Oページフォルトが起こるとスレッドが固まるので、その点からも、非同期プログラム*1では mmap を避けて非同期 I/O システムコールを使うべきです。

かっとなって書いたが後悔はしていない。

*1:Goって非同期プログラミングするための言語ですよね