【Golang】fmt.Scanとbufio.Scannerの速度比較
たとえ競技プログラミングに興味がなくても、読み込み書き込み速度は大量のデータをさばくときには重要になります。
ってことで、fmt.Scan()とbufio.Scanの処理速度と書きやすさを比較してみる。
ちなみに例題として、1行目に何個のデータが与えられるかのn、2行目にスペース区切りでn個の数値が与えられる。n個の数値の合計を求めるって問題で。
fmt.Scan
code:golang
func FmtScan() {
var n, sum int
_, _ = fmt.Scan(&n)
for i := 0; i < n; i++ {
var a int
_, _ = fmt.Scan(&a)
sum += a
}
fmt.Println(sum)
}
fmt.Scanはスペースか改行が入力されるまでの内容を取得するための関数。
「int型のaに読み込んだ値を入れてねー」ってだけなので、結構直感的に使える印象。
int型でもfloat型でもstring型でも対応していますし、引数を任意の個数与えられるので、自由度も高い!
bufio.Scan
code:golang
func ScanWords() {
sc := bufio.NewScanner(os.Stdin)
sc.Split(bufio.ScanWords)
sc.Scan()
n, _ := strconv.Atoi(sc.Text())
sum := 0
for i := 0; i < n; i++ {
sc.Scan()
a, _ := strconv.Atoi(sc.Text())
sum += a
}
fmt.Println(sum)
}
bufio.Scanは指定したReaderから読み込むための関数なので、標準入力に限らずファイルからの読み込みとかもできる。
ただし基本的にstring型なので、intやfloatを使いたい場合はparseしてあげる必要がある。
あとsc.Split(bufio.ScanWords)を指定しなければ、デフォルトではbufio.ScanLinesになっていて、行区切りのみ。
fmt.Scanと比べるとコード量が増えがち。
速度比較
table:速度比較
データ数 fmt.Scan bufio.Scan
10 0.494s 0.484s
100 0.521s 0.505s
1000 0.501s 0.503s
10000 0.512s 0.498s
100000 0.798s 0.519s
1000000 3.110s 0.519s
2000000 5.749s 0.549s
4000000 11.146s 0.612s
1万データくらいまではほとんど同じで簡単に書けるfmt.Scanのほうが使いやすいんですが、
10万データをこえたあたりから、fmt.Scanがあきらかに遅くなる。
それに比べてbufio.Scanは大きな速度劣化が起こらないから安定して使える。
10万データ以下であれば型変換が不要で使い勝手のいいfmt.Scan、10万データ以上であれば速度重視のbufio.Scanで決まりですかね!!
最終更新日: 2019/02/18