Rustが得意なフレンズになりたくて、人の書いたCのコードを、Rustに写経しています。
で、作っていたら、ファイルI/Oが、悲惨なレベルで遅いことに気づきました。
use std::fs;
use std::io::Write;
fn main() {
let b = b"test";
let mut f = fs::File::create("rs.dump").unwrap();
for _ in 0 .. 100_000_000 {
f.write(b).unwrap();
}
}
use std::{fs, mem};
use std::io::Read;
fn main() {
let mut f = fs::File::open("rs.dump").unwrap();
let mut b: [u8; 4] = unsafe { mem::uninitialized() };
for _ in 0 .. 100_000_000 {
f.read_exact(&mut b).unwrap();
}
}
何が悪いか、分かりますか? まぁ、タイトル読めば分かりますよね。
実は、Rustのファイルのwrite, read_exactは、バッファリングされていません。
なので、このコードは、4バイトずつ読み書きするために10万回のシステムコールを呼び出します。
じゃあCのfread, fwriteは? そっちはバッファリングされているらしいのです。
標準入出力ライブラリは、簡単かつ効果のよい、 バッファーリングされたストリーム入出力インターフェースを提供する。
ふぇぇ、manページの最初に書いてあるのに、知らなかったし、考えたこともなかった。
そういうわけなので。ファイルI/Oでは std::io::{BufReader, BufWriter}
を使うとCと互角の速度になりました。
use std::fs;
use std::io::{BufWriter, Write};
fn main() {
let b = b"test";
let mut f = BufWriter::new(fs::File::create("rs.dump").unwrap());
for _ in 0 .. 100_000_000 {
f.write(b).unwrap();
}
}
use std::{fs, mem};
use std::io::{BufReader, Read};
fn main() {
let mut f = BufReader::new(fs::File::open("rs.dump").unwrap());
let mut b: [u8; 4] = unsafe { mem::uninitialized() };
for _ in 0 .. 100_000_000 {
f.read_exact(&mut b).unwrap();
}
}
Special Thanks
本気で原因分からなかったので、StackOverflowで質問し、教えていただきました。
http://stackoverflow.com/questions/43028653/rust-file-i-o-is-very-slow-compared-with-c-is-something-wrong/43029048