【Go】reflectパッケージを使用した処理のベンチマークテスト

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

タグ:Go

概要

DBからレコードを取得してテキストファイルに出力する処理の中でreflectパッケージを使っていたが、パフォーマンス的によろしくないという情報が多かったで使わないようにした。

実際にどのくらいパフォーマンスが違うのか気になったのでベンチマークテストを行ってみた。

環境

計測方法

サンプルコード

reflectパッケージ使用

func BenchmarkFileOutPutTodosWithRefrect(b *testing.B) { db, _ := dbConn() b.ReportAllocs() for i := 0; i < b.N; i++ { FileOutPutTodosWithRefrect(db, "file_output.txt") os.Remove("file_output.txt") } } func FileOutPutTodosWithRefrect(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 { val := reflect.ValueOf(todo) typ := val.Type() var fields []string for i := 0; i < typ.NumField(); i++ { key := typ.Field(i).Name value := fmt.Sprintf("%v", val.Field(i).Interface()) fields = append(fields, fmt.Sprintf("%v: %v", key, value)) } _, err := fmt.Fprintf(file, "{%s},\n", strings.Join(fields, ", ")) if err != nil { return err } } return nil }

reflectパッケージ不使用

func BenchmarkFileOutPutTodos(b *testing.B) { db, _ := dbConn() b.ReportAllocs() for i := 0; i < b.N; i++ { FileOutPutTodos(db, "file_output.txt") os.Remove("file_output.txt") } } func FileOutPutTodos(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 }

計測結果

=== RUN BenchmarkFileOutPutTodosWithRefrect BenchmarkFileOutPutTodosWithRefrect BenchmarkFileOutPutTodosWithRefrect-8 18 63923287 ns/op 24169018 B/op 669901 allocs/op === RUN BenchmarkFileOutPutTodos BenchmarkFileOutPutTodos BenchmarkFileOutPutTodos-8 34 33159001 ns/op 11290029 B/op 249605 allocs/op

reflectパッケージ使用(BenchmarkFileOutPutTodosWithRefrect)

reflectパッケージ不使用(BenchmarkFileOutPutTodos)

比較

reflect使用reflect不使用比較
実行回数18回34回約1.9倍 増
平均実行時間63,923,287 ns/op(約63.9ms/1回)33,159,001 ns/op(33.5ms/1回)約48.1% 減
メモリ使用量24,169,018 B/op(約24MB/1回)11,290,029 B/op(約11MB/1回約53.3% 減
メモリアロケーション回数669,901回249,605回約62.7% 減

結論