【VB.Net】CallByNameの速度検証

はじめに


今回はVB.NetのCallByNameの参照速度を検証してみる。 CallByNameは指定したインスタンスが所有するメソッドやプロパティを文字列から取得する関数。 遅延評価であるため(?)、べた書きより遅いとされる。ではどのくらい遅いのか。

結果


プロパティの呼び出しをCallByNameとべた書きでそれぞれ100万回ずつ行った。 結果としてCallByNameはべた書きに対し、100倍以上時間がかかることがわかった。 データ数が少なければ体感として時間差は感じないかもしれないが、レコードが1万、 カラムが100個のテーブルを更新するなんてことがあった場合は、さすがに体感でもわかる時間差になる。

手法 時間(s)
CallByName 4.672
べた書き 0.044
CallMembersWithCallByName ---Start
total(1000000): 4.672 [s]
CallMembersWithCallByName ---End

CallMembers ---Start
total(1000000): 0.044 [s]
CallMembers ---End

CallByName / BetaGaki = 106.18181818181819

付録

今回使用したコード

Imports System


Class TestClass
#Region "【メンバ変数】"
    Private m_A As String = "A"
    Private m_B As String = "B"
    Private m_C As String = "C"
    Private m_D As String = "D"
    Private m_E As String = "E"
#End Region
#Region "【プロパティ】"
    Public ReadOnly Property A() As String
        Get
            Return m_A
        End Get
    End Property
    Public ReadOnly Property B() As String
        Get
            Return m_B
        End Get
    End Property
    Public ReadOnly Property C() As String
        Get
            Return m_C
        End Get
    End Property
    Public ReadOnly Property D() As String
        Get
            Return m_D
        End Get
    End Property
    Public ReadOnly Property E() As String
        Get
            Return m_E
        End Get
    End Property
#End Region
#Region "【メソッド】"
    ''' <summary>
    ''' CallByNameを使用してプロパティを呼び出す
    ''' </summary>
    Public Sub CallMembersWithCallByName()
        For Each m In New String() {"A", "B", "C", "D", "E"}
            CallByName(Me, m, CallType.Get)
        Next
    End Sub

    ''' <summary>
    ''' 通常通りにプロパティを呼び出す
    ''' </summary>
    Public Sub CallMembers()
        For Each m In New String() {A, B, C, D, E}  ' ←ここで呼び出し

        Next
    End Sub
#End Region
End Class

Module Program

    ' デリゲート
    Delegate Sub Processing()

    ''' <summary>
    ''' ベンチマーク(時間計測のみ)
    ''' </summary>
    ''' <param name="times">処理回数</param>
    ''' <param name="subpro">テスト対象(Subプロシージャ)</param>
    ''' <returns></returns>
    Function BenchMark(times As Long, subpro As Processing) As Double
        ' 関数名取得
        Dim methodName As String = subpro.Method.Name()
        Console.WriteLine(methodName & " ---Start")

        ' ストップウォッチ
        Dim sw As New Stopwatch()
        sw.Start()
        For i = 1 To times
            subpro.Invoke()
        Next
        sw.Stop()

        ' ミリ秒 to 秒
        Dim seconds As Double = sw.ElapsedMilliseconds / 10 ^ 3
        Console.WriteLine("total(" & times & "): " & seconds & " [s]")

        Console.WriteLine(methodName & " ---End")
        Console.WriteLine()

        Return seconds
    End Function

    Sub Main(args As String())
        ' 処理回数
        Dim times As Long = 10 ^ 6

        ' テストクラス
        Dim clsTest As New TestClass()

        ' ベンチマーク(処理時間(s)を受け取る)
        Dim CallByNameSeconds As Double = BenchMark(times, AddressOf clsTest.CallMembersWithCallByName)
        Dim BetaGakiSeconds As Double = BenchMark(times, AddressOf clsTest.CallMembers)

        ' 倍率を表示
        Console.WriteLine("CallByName / BetaGaki = " & CallByNameSeconds / BetaGakiSeconds)

    End Sub
End Module

更新日時: