【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