1
1

More than 3 years have passed since last update.

【Go言語】型アサーション vs リフレクション シンプルなベンチマーク

Posted at

はじめに

Goでのリフレクションはパフォーマンスに影響するので注意と耳にするがどんなものかベンチマークを取る。

今回のサンプルケース

型としてinterface{}な実態が[]stringな値を引数に[]stringを返す関数。

リフレクションを使う場合と型アサーションを使う場合でベンチマークを取ってみた。

vs_test.go
package main

import (
    "reflect"
    "strconv"
    "testing"
)

var input []interface{}

func init() {
    for i := 1; i <= 10000; i++ {
        input = append(input, strconv.Itoa(i))
    }
}

// リフレクションを使う関数 は`interface{}`型で受け取りリフレクションをするので
// 柔軟に引数の値をさばくことができる。
func リフレクションを使う関数(target interface{}) []string {
    if target == nil {
        return nil
    }

    v := reflect.ValueOf(target)

    switch v.Kind() {
    case reflect.Slice:
        ret := make([]string, v.Len())
        for i := 0; i < v.Len(); i++ {
            x := v.Index(i)
            k := x.Kind()
            if k == reflect.Interface || k == reflect.String {
                s, ok := x.Interface().(string)
                if ok {
                    ret[i] = s
                }
            }
        }
        return ret
    case reflect.String: // stringが引数の場合はそれをスライスにして返す。
        return []string{v.String()}
    default:
        return nil
    }
}

// 型アサーションを使う関数 はスライスであることを決め打ちしたうえで`[]string`
// に変換して返す関数である。
func 型アサーションを使う関数(target []interface{}) []string {
    ret := make([]string, len(target))
    for i, r := range target {
        s, ok := r.(string)
        if ok {
            ret[i] = s
        }
    }
    return ret
}

func Benchmark_リフレクション(b *testing.B) {
    var target interface{}
    target = input
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        リフレクションを使う関数(target)
    }
}

func Benchmark_型アサーション(b *testing.B) {
    var target interface{}
    target = input
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        型アサーションを使う関数(target.([]interface{}))
    }
}

結果

速度において型アサーションがリフレクションよりも3倍強速かった。メモリ利用は差は無し。

この3倍をどう捉えるかはシステム要件次第であるが選択肢に入れられないほどパフォーマンスが悪いわけではない。

$ go test -bench . -benchmem
goos: darwin
goarch: amd64
Benchmark_リフレクション-4                          6013            204633 ns/op          163840 B/op          1 allocs/op
Benchmark_型アサーション-4                         18973             61017 ns/op          163842 B/op          1 allocs/op
PASS
ok      go-comparison/typeassert_vs_reflection        4.431s

感想

テストの関数に日本語を使うのは違和感が無いが、アプリケーションコードの関数を日本語にするのは変に感じる。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1