【Go】ファイルへの書き込みをバッファリングに修正してみた

更新日:2025/3/13/(木) 12:38

タグ:Go

概要

DBからレコードを取得してテキストファイルに出力する処理の中でfmt.Fprintfを使用している箇所をbufio.Writer のバッファリングを利用するように修正してみた。

どのくらいパフォーマンスが向上したのかベンチマークテストも行ってみた。

環境

計測方法

サンプルコード

fmt.Fprintf使用

func BenchmarkFprintf(b *testing.B) { db, _ := dbConn() b.ReportAllocs() for i := 0; i < b.N; i++ { FileOutPutTodosWithFprintf(db, "file_output.txt") os.Remove("file_output.txt") } } func FileOutPutTodosWithFprintf(db *gorm.DB, fileName string) error { file, err := os.Create(fileName) if err != nil { return err } defer file.Close() var todos []Todo result := db.Find(&todos) if result.Error != nil { return result.Error } for _, todo := range todos { fields := []string{ fmt.Sprintf("ID: %v", todo.ID), fmt.Sprintf("Title: %v", todo.Title), fmt.Sprintf("Note: %v", todo.Note), } _, err := fmt.Fprintf(file, "{%s},\n", strings.Join(fields, ", ")) if err != nil { return err } } return nil }

bufio.Writer使用

func BenchmarkBufio(b *testing.B) { db, _ := dbConn() b.ReportAllocs() for i := 0; i < b.N; i++ { FileOutPutTodosWithBufio(db, "file_output.txt") os.Remove("file_output.txt") } } func FileOutPutTodosWithBufio(db *gorm.DB, fileName string) error { file, err := os.Create(fileName) if err != nil { return err } defer file.Close() writer := bufio.NewWriter(file) defer writer.Flush() var todos []Todo result := db.Find(&todos) if result.Error != nil { return result.Error } for _, todo := range todos { fields := []string{ fmt.Sprintf("ID: %v", todo.ID), fmt.Sprintf("Title: %v", todo.Title), fmt.Sprintf("Note: %v", todo.Note), } line := fmt.Sprintf("{%s},\n", strings.Join(fields, ", ")) _, err = writer.Write([]byte(line)) if err != nil { return err } } return nil }

計測結果

=== RUN BenchmarkFprintf BenchmarkFprintf BenchmarkFprintf-8 31 33787055 ns/op 11289062 B/op 249601 allocs/op === RUN BenchmarkBufio BenchmarkBufio BenchmarkBufio-8 61 19502351 ns/op 13212685 B/op 269613 allocs/op

fmt.Fprintf使用(BenchmarkFprintf)

bufio.Writer使用(BenchmarkBufio)

比較

fmt.Fprintf使用bufio.Writer使用比較
実行回数31回61回約1.9倍 増
平均実行時間33,787,055 ns/op(約33.8ms/1回)19,502,351 ns/op(19.5ms/1回)約42.2% 減
メモリ使用量11,289,062 B/op(約11.2MB/1回)13,212,685 B/op(約13.2MB/1回)約17.0% 増
メモリアロケーション回数249,601回269,613回約8.0% 増

パフォーマンスの差の要因

I/O回数がfmt.Fprintf使用にくらべてbufio.Writer使用の方が少ないことが要因か

結論