none
boxing的問題 RRS feed

  • 問題

  • 大家好:

          最近發現程式中型別轉換會讓程式效率產生極大的差別 , 想請教大家的問題是 , 以下bb(1) = 123這一行是否會產生型別轉換而影響程式效率(在大量重覆迴圈下) , 如果是 ? 這種型別轉換是所謂的boxing嗎? 以此程式碼為例 , 該如何解決? 先感謝所有提供討論意見的高手.

    ---------------------

            Dim aa As String = " 123 11 22 33 44 55"
            Dim bb As Array
            bb = Split(aa, " ")

            If bb(1) = 123 Then
                MsgBox("ok")
            End If

    --------------------

    2012年7月23日 上午 02:52

解答

  • 您好

    是,請參考 ToString() ? Boxing ?

    以下是 IL 檔案內容,你可以參考看看

      IL_0014:  stloc.1
      IL_0015:  ldloc.1
      IL_0016:  ldc.i4.1
      IL_0017:  newarr     [mscorlib]System.Object
      IL_001c:  stloc.2
      IL_001d:  ldloc.2
      IL_001e:  ldc.i4.0
      IL_001f:  ldc.i4.1
      IL_0020:  box        [mscorlib]System.Int32
      IL_0025:  stelem.ref
      IL_0026:  nop
      IL_0027:  ldloc.2
      IL_0028:  ldnull
      IL_0029:  call       object [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.NewLateBinding::LateIndexGet(object,
                                                                                                                             object[],
                                                                                                                             string[])
      IL_002e:  ldc.i4.s   123
      IL_0030:  box        [mscorlib]System.Int32
      IL_0035:  ldc.i4.0
      IL_0036:  call       bool [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::ConditionalCompareObjectEqual(object,
                                                                                                                                       object,
                                                                                                                                       bool)


    歡迎參觀我的Blog.NET菜鳥自救會


    2012年7月23日 上午 03:39
    版主

所有回覆

  • 您好

    是,請參考 ToString() ? Boxing ?

    以下是 IL 檔案內容,你可以參考看看

      IL_0014:  stloc.1
      IL_0015:  ldloc.1
      IL_0016:  ldc.i4.1
      IL_0017:  newarr     [mscorlib]System.Object
      IL_001c:  stloc.2
      IL_001d:  ldloc.2
      IL_001e:  ldc.i4.0
      IL_001f:  ldc.i4.1
      IL_0020:  box        [mscorlib]System.Int32
      IL_0025:  stelem.ref
      IL_0026:  nop
      IL_0027:  ldloc.2
      IL_0028:  ldnull
      IL_0029:  call       object [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.NewLateBinding::LateIndexGet(object,
                                                                                                                             object[],
                                                                                                                             string[])
      IL_002e:  ldc.i4.s   123
      IL_0030:  box        [mscorlib]System.Int32
      IL_0035:  ldc.i4.0
      IL_0036:  call       bool [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::ConditionalCompareObjectEqual(object,
                                                                                                                                       object,
                                                                                                                                       bool)


    歡迎參觀我的Blog.NET菜鳥自救會


    2012年7月23日 上午 03:39
    版主
  • 您好,

    您可改成

    Dim aa As String = " 123 11 22 33 44 55"
    Dim bb() As String
    bb = Split(aa, " ")
    
    If bb(1) = 123 Then
        MsgBox("ok")
    End If

    或是直接用String做比較

    Dim aa As String = " 123 11 22 33 44 55"
    Dim bb() As String
    bb = Split(aa, " ")
    
    If bb(1) = "123" Then
    	MsgBox("ok")
    End If


    以上說明若有錯誤請指教,謝謝。
    亂馬客blog: http://www.dotblogs.com.tw/rainmaker/

    2012年7月23日 上午 03:46
  • 您好,

    您可改成

    Dim aa As String = " 123 11 22 33 44 55"
    Dim bb() As String
    bb = Split(aa, " ")
    
    If bb(1) = 123 Then
        MsgBox("ok")
    End If

    或是直接用String做比較

    Dim aa As String = " 123 11 22 33 44 55"
    Dim bb() As String
    bb = Split(aa, " ")
    
    If bb(1) = "123" Then
    	MsgBox("ok")
    End If


    以上說明若有錯誤請指教,謝謝。
    亂馬客blog: http://www.dotblogs.com.tw/rainmaker/

    因為split之後要比較的型別是int , 所以我曾嘗試以下寫法 , 但因為spilt分割出來的是字串型別 , 所以程式會出現error , 謝謝亂馬客的回覆 , 但第一種解決方式應該還是會有boxing.

    Dim aa As String = " 123 11 22 33 44 55"
    Dim bb() As Integer

    dim ans as integer = 123

    bb = Split(aa, " ")

    If bb(1) = ans  Then
        MsgBox("ok")
    End If 

    2012年7月23日 上午 05:48
  •  您好,
    請問您如何得知第1種方式有boxing呢? 我看iL它是做 Conversions .
    您可以透過 iLdasm程式去看是不是有做boxing哦!
    第1種方式的iL如下,

    .method private instance void  Button1_Click(object sender,
                                                 class [mscorlib]System.EventArgs e) cil managed
    {
      // 程式碼大小       60 (0x3c)
      .maxstack  4
      .locals init ([0] string aa,
               [1] string[] bb,
               [2] bool VB$CG$t_bool$S0)
      IL_0000:  nop
      IL_0001:  ldstr      " 123 11 22 33 44 55"
      IL_0006:  stloc.0
      IL_0007:  ldloc.0
      IL_0008:  ldstr      " "
      IL_000d:  ldc.i4.m1
      IL_000e:  ldc.i4.0
      IL_000f:  call       string[] [Microsoft.VisualBasic]Microsoft.VisualBasic.Strings::Split(string,
                                                                                                string,
                                                                                                int32,
                                                                                                valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.CompareMethod)
      IL_0014:  stloc.1
      IL_0015:  ldloc.1
      IL_0016:  ldc.i4.1
      IL_0017:  ldelem.ref
      IL_0018:  call       float64 [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Conversions::ToDouble(string)
      IL_001d:  ldc.r8     123.
      IL_0026:  ceq
      IL_0028:  stloc.2
      IL_0029:  ldloc.2
      IL_002a:  brfalse.s  IL_0039
      IL_002c:  ldstr      "ok"
      IL_0031:  ldc.i4.0
      IL_0032:  ldnull
      IL_0033:  call       valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult [Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::MsgBox(object,
                                                                                                                                                                valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle,
                                                                                                                                                                object)
      IL_0038:  pop
      IL_0039:  nop
      IL_003a:  nop
      IL_003b:  ret
    } // end of method Form1::Button1_Click

    以上說明若有錯誤請指教,謝謝。
    亂馬客blog: http://www.dotblogs.com.tw/rainmaker/



    • 已編輯 亂馬客 2012年7月23日 上午 07:24
    2012年7月23日 上午 07:22
  •  您好,
    請問您如何得知第1種方式有boxing呢? 我看iL它是做 Conversions .
    您可以透過 iLdasm程式去看是不是有做boxing哦!
    第1種方式的iL如下,

    .method private instance void  Button1_Click(object sender,
                                                 class [mscorlib]System.EventArgs e) cil managed
    {
      // 程式碼大小       60 (0x3c)
      .maxstack  4
      .locals init ([0] string aa,
               [1] string[] bb,
               [2] bool VB$CG$t_bool$S0)
      IL_0000:  nop
      IL_0001:  ldstr      " 123 11 22 33 44 55"
      IL_0006:  stloc.0
      IL_0007:  ldloc.0
      IL_0008:  ldstr      " "
      IL_000d:  ldc.i4.m1
      IL_000e:  ldc.i4.0
      IL_000f:  call       string[] [Microsoft.VisualBasic]Microsoft.VisualBasic.Strings::Split(string,
                                                                                                string,
                                                                                                int32,
                                                                                                valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.CompareMethod)
      IL_0014:  stloc.1
      IL_0015:  ldloc.1
      IL_0016:  ldc.i4.1
      IL_0017:  ldelem.ref
      IL_0018:  call       float64 [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Conversions::ToDouble(string)
      IL_001d:  ldc.r8     123.
      IL_0026:  ceq
      IL_0028:  stloc.2
      IL_0029:  ldloc.2
      IL_002a:  brfalse.s  IL_0039
      IL_002c:  ldstr      "ok"
      IL_0031:  ldc.i4.0
      IL_0032:  ldnull
      IL_0033:  call       valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult [Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::MsgBox(object,
                                                                                                                                                                valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle,
                                                                                                                                                                object)
      IL_0038:  pop
      IL_0039:  nop
      IL_003a:  nop
      IL_003b:  ret
    } // end of method Form1::Button1_Click

    以上說明若有錯誤請指教,謝謝。
    亂馬客blog: http://www.dotblogs.com.tw/rainmaker/



          謝謝 亂馬客 的回應 , 其實我也不知道你第一種程式是否會有boxing ,   但我做了簡單的實驗(程式碼如下) ,  執行時間(小筆電上)約17秒 , 但如果把它改成你的第二種程式碼 bb(1)="123" , 則約只需6秒 , 如果改成 Ctype(bb(1),Integer)=123 則也是約17秒 , 我想只要涉及型別轉換, 執行效率就會受很大的影響. 以這個例子而言 , 如果split後的array是int型別 , 就應該可以解決這個問題.以上提供大家參考. 如實驗有誤 , 請不吝指正.

           Dim t_s As Long = Now.Ticks

            Dim aa As String = " 123 11 22 33 44 55"
            Dim bb() As String

            For i = 1 To 10000000

                bb = Split(aa, " ")
                If bb(1) = 123 Then

                End If
            Next
            MsgBox(Format((Now.Ticks - t_s) / 10000000, "0.0000000") & "s")


    2012年7月23日 上午 08:19
  •     如果參考小歐的資料 , 將 if bb(1) = 123 改成以下方式(cc.ToString) ,則執行時間會從17秒減為7秒左右 , 顯然採用tostring的型別轉換 , 不會影響程式效率 , 提供大家參考.

    ----------------------------------------

          Dim t_s As Long = Now.Ticks

            Dim aa As String = " 123 11 22 33 44 55"
            Dim bb() As String
            Dim cc As Integer = 123
            For i = 1 To 10000000

                bb = Split(aa, " ")
                If bb(1) = cc.ToString Then

                End If
            Next
            MsgBox(Format((Now.Ticks - t_s) / 10000000, "0.0000000") & "s") 

    2012年7月23日 上午 08:36
  • 原來您是用執行的時間來判斷呀!

    其實看iL會比較清楚。

    因為那2個比較慢的原因並不是做了Boxing & UnBoxing,而是做了型態的轉換所花的時間,較慢的那個是因為做了implicit conversion。

    您可以試著改用 Integer.Parse(bb(1))

    If bb(1) = cc.ToString Then
    =>
    If Integer.Parse(bb(1)) = cc Then

    或是用Val(bb(1))

    If bb(1) = cc.ToString Then
    =>

    If Val(bb(1)) Then

    以上如果您使用Val的話,速度應該會是最快的哦!

    相關說明,請參考:[.NET]VB.NET中轉換成數值方式比較


    以上說明若有錯誤請指教,謝謝。
    亂馬客blog: http://www.dotblogs.com.tw/rainmaker/




    • 已編輯 亂馬客 2012年7月24日 上午 04:47
    2012年7月23日 下午 03:39
  • 使用val函數確實可以達成轉換字串為數值 , 而且不影響效率 , 謝謝亂馬客的回覆.
    2012年7月24日 上午 04:11