2008/08/26

データ変換速度比較

VB.NET/.NetFramwork2で型変換の速度差、特色について気になりだしたので、実験してみました。

興味があった変換は、普段よく使う

  • Object→Int32への変換
  • String→Int32への変換

です。

実験したものはCtype、CInt、DirectCast、Convert.ToInt32、Int32.Parse、 Int32.TryParse。

実験結果としてはこんな感じです。【 】の中の数値はObjectなりStringなりのmyData変数を、それぞれのメソッドなりでの変換したものです。Int32.TryParseで【 0】となっているのは、変換できなかったということですね。

実験結果

(速度の早い順に並び替え)
Dim my_Data As Object = 12345
DirectCast :        【     12345】00:00:00.0004363
CInt :              【     12345】00:00:00.0023329 'CtypeとCInt、Convert.ToInt32は順位が入れ替わるときがあります。
CType :             【     12345】00:00:00.0023815
Convert.ToInt32 :   【     12345】00:00:00.0030900
Int32.Parse :       【     12345】00:00:00.0468925 'Int32.ParseとInt32.TryParseは順位が入れ替わるときがあります。
Int32.TryParse :    【     12345】00:00:00.0475714


Dim my_Data As Object = 12345.5
CInt :              【     12346】00:00:00.0039555
CType :             【     12346】00:00:00.0040038
Convert.ToInt32 :   【     12346】00:00:00.0052587
Int32.TryParse :    【         0】00:00:00.0631435


Dim my_Data As String = "12345"
Int32.Parse :       【     12345】00:00:00.0198393
Int32.TryParse :    【     12345】00:00:00.0206115
Convert.ToInt32 :   【     12345】00:00:00.0214960
CType :             【     12345】00:00:01.7970309
CInt :              【     12345】00:00:01.7990923


Dim my_Data As String = "12345.5"
Int32.TryParse :    【         0】00:00:00.0198050
CInt :              【     12346】00:00:01.8433437
CType :             【     12346】00:00:01.8474300

所感としては、Object型のときは、DirectCastを使うのが一番高速(但しDirectCastは丸め処理などは行わず、Int32に変換するのに小数などを引数に渡すとエラーを吐きます)。String型のときは、Int32.Parseが一番高速…、というところでしょうかね。現実問題としてはInt32.TryParseも、使い勝手がよさそうです。

サンプルソース

▲TextBox1に結果が出るわけです…。

※Int32.Parseの引数はもともとString型なので、Option StrictはOffにしないと走りません。

Imports System.Diagnostics


Public Class Form1
    Private Sub Button1_Click(ByVal sender As Object, _
                              ByVal e As System.EventArgs) _
                              Handles Button1.Click

        Dim sw As New Stopwatch
        Dim sb_Data As New System.Text.StringBuilder
        Dim bl_result As Boolean
        Dim my_Dict As New Dictionary(Of String, String)


        Dim my_Data As Object = 12345  '#---ここをあれこれ差し替えました。
        '                                   少数の値をセットしたりして
        '                                   エラーができるときは、
        '                                   型変換部分も
        '                                   コメントアウトします。
        Dim int_Data As Int32

        '----------------------------------
        sw.Reset()
        sw.Start()
        For i As Int32 = 0 To 100000
            int_Data = CType(my_Data, Int32)
        Next
        sw.Stop()
        my_Dict.Add("CType" & vbTab _
                    & int_Data.ToString, _
                    sw.Elapsed.ToString)
        '----------------------------------
        sw.Reset()
        sw.Start()
        For i As Int32 = 0 To 100000
            int_Data = CInt(my_Data)
        Next
        sw.Stop()
        my_Dict.Add("CInt" & vbTab _
                    & int_Data.ToString, _
                    sw.Elapsed.ToString)
        '----------------------------------
        sw.Reset()
        sw.Start()
        For i As Int32 = 0 To 100000
            int_Data = DirectCast(my_Data, Int32)
        Next
        sw.Stop()
        my_Dict.Add("DirectCast" & vbTab _
                    & int_Data.ToString, _
                    sw.Elapsed.ToString)
        '----------------------------------
        sw.Reset()
        sw.Start()
        For i As Int32 = 0 To 100000
            int_Data = Convert.ToInt32(my_Data)
        Next
        sw.Stop()
        my_Dict.Add("Convert.ToInt32" & vbTab _
                    & int_Data.ToString, _
                    sw.Elapsed.ToString)
        '----------------------------------
        sw.Reset()
        sw.Start()
        For i As Int32 = 0 To 100000
            int_Data = Int32.Parse(my_Data)
        Next
        sw.Stop()
        my_Dict.Add("Int32.Parse" & vbTab _
                    & int_Data.ToString, _
                    sw.Elapsed.ToString)
        '----------------------------------
        sw.Reset()
        sw.Start()
        For i As Int32 = 0 To 100000
            bl_result = Int32.TryParse(my_Data, _
                                       int_Data)
        Next
        sw.Stop()
        my_Dict.Add("Int32.TryParse" & vbTab _
                    & int_Data.ToString, _
                    sw.Elapsed.ToString)
        '----------------------------------

        Dim sorted As List(Of KeyValuePair(Of String, String)) _
                = sortByValue(my_Dict)

        sorted.Reverse()

        For Each kvp As KeyValuePair(Of String, String) In sorted

            Dim str_SPL() As String _
                = kvp.Key.Split(vbTab.ToCharArray)
            Dim str_Num As String _
            = Strings.StrDup(10, " ") & str_SPL(1)

            sb_Data.Append((str_SPL(0) & " :" _
              & Strings.StrDup(20, " ")).Substring(0, 20) _
              & "【" & (str_Num).Substring(str_Num.Length - 10, 10) & "】" _
              & kvp.Value & vbCrLf)

        Next

        Me.TextBox1.Text = sb_Data.ToString
        sb_Data.Remove(0, sb_Data.Length)
        sb_Data = Nothing

    End Sub


    Shared Function hikaku(Of TKey, TValue As IComparable(Of TValue))( _
      ByVal kvp1 As KeyValuePair(Of TKey, TValue), _
      ByVal kvp2 As KeyValuePair(Of TKey, TValue)) As Integer

        Return kvp2.Value.CompareTo(kvp1.Value)
    End Function


    Shared Function sortByValue(Of TKey, TValue As IComparable(Of TValue))( _
      ByVal dict As Dictionary(Of TKey, TValue)) _
      As List(Of KeyValuePair(Of TKey, TValue))

        Dim list As New List(Of KeyValuePair(Of TKey, TValue))(dict)

        'Valueの大きい順にソート
        list.Sort(AddressOf hikaku)
        Return list
    End Function
End Class

0 件のコメント: