加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

.net – 使用array.resize而不是redim的原因

发布时间:2020-12-17 00:01:35 所属栏目:大数据 来源:网络整理
导读:我知道“redim”比“Array.Resize”更旧,但是不明白将后者用于前者的原因. 除非添加“保留”修改器,否则无法比较 ReDim和 Array.ResizeT. Array.Resize不仅会分配新数组,还会将源数组中的所有项目复制到目标数组. 没有Preserve修饰符的ReDim只会分配一个新数
我知道“redim”比“Array.Resize”更旧,但是不明白将后者用于前者的原因.
除非添加“保留”修改器,否则无法比较 ReDim和 Array.Resize<T>.

Array.Resize不仅会分配新数组,还会将源数组中的所有项目复制到目标数组.

没有Preserve修饰符的ReDim只会分配一个新数组.源数组中的所有项都将丢失.

基本上这个:

Dim a As String() = {"item1","item2"}
ReDim a(4 - 1) 'Double the size
'At this point,a contains 4 null references.

……等于这个:

Dim a As String() = {"item1","item2"}
a = New String(4 - 1) {} 'Double the size
'At this point,a contains 4 null references.

您可以通过检查发布配置中生成的CIL代码来验证这一点,并查找0x8D – newarr <etype>指令.通过了解这一点,很明显为什么它比Array.Resize< T>更快.

因此,让我们比较ReDim Preserve和Array< T>.

So which one to use?

让我们创建两个方法并查看CIL代码.

VB.NET

Private Sub ResizeArray1(Of T)(ByRef a As T(),size As Int32)
    ReDim Preserve a(size - 1)
End Sub

Private Sub ResizeArray2(Of T)(ByRef a As T(),size As Int32)
    Array.Resize(a,size)
End Sub

CIL

.method private static void ResizeArray1<T>(!!T[]& a,int32 size) cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: ldarg.0 
    L_0002: ldind.ref 
    L_0003: ldarg.1 
    L_0004: ldc.i4.1 
    L_0005: sub.ovf 
    L_0006: ldc.i4.1 
    L_0007: add.ovf 
    L_0008: newarr !!T
    L_000d: call class [mscorlib]System.Array [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Utils::CopyArray(class [mscorlib]System.Array,class [mscorlib]System.Array)
    L_0012: castclass !!T[]
    L_0017: stind.ref 
    L_0018: ret 
}

.method private static void ResizeArray2<T>(!!T[]& a,int32 size) cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: ldarg.1 
    L_0002: call void [mscorlib]System.Array::Resize<!!T>(!!0[]&,int32)
    L_0007: ret 
}

如您所见,ReDim Preserve最终作为Microsoft.VisualBasic.CompilerServices.Utils.CopyArray的调用指令.现在,如果您检查CopyArray(源代码在RS不可用)和Array.Resize<T>,您将看到两个方法最终都作为Array.Copy<T>的调用指令,即CLR方法.

所以人们可以争辩说它们本质上都是“相同的”,并且快速的benckmark(在这篇文章的最后可用)似乎证实了这一点.

但是,正如Hans Passant正确指出的那样,无论何时需要操作数组,都应该使用List<T>.

基准

Iterations: 10
MaxSize: 100000

Empty source array:

{ Method = ResizeArray1,Time = 00:00:05.6533126 }
{ Method = ResizeArray2,Time = 00:00:05.6973607 }

Growing source array:

{ Method = ResizeArray1,Time = 00:01:42.6964858 }
{ Method = ResizeArray2,Time = 00:01:42.1891668 }

Option Strict On

Public Module Program

    Friend Sub Main()
        Console.WriteLine("Warming up...")
        Program.Benchmark(iterations:=10,maxSize:=1000,warmUp:=True)
        Console.WriteLine("Warmup completed. Measurement started...")
        Program.Benchmark(iterations:=10,maxSize:=100000,warmUp:=False)
        Console.WriteLine()
        Console.WriteLine("Measurement completed. Press any key to exit.")
        Console.ReadKey()
    End Sub

    Private Sub Benchmark(iterations As Int32,maxSize As Int32,warmUp As Boolean)

        Dim watch As Stopwatch
        Dim a As String()

        'BY: EMPTY SOURCE ARRAY --------------------------------- 

        'Resize array #1

        watch = Stopwatch.StartNew()

        For i As Int32 = 1 To iterations
            For n As Int32 = 1 To maxSize
                a = Program.CreateArray(Of String)(0)
                Program.ResizeArray1(a,n)
            Next
        Next

        watch.Stop()

        If (Not warmUp) Then
            Console.WriteLine()
            Console.WriteLine(String.Format("R E S U L T"))
            Console.WriteLine()
            Console.WriteLine(String.Format("Iterations: {0}",iterations))
            Console.WriteLine(String.Format("   MaxSize: {0}",maxSize))
            Console.WriteLine()
            Console.WriteLine("Empty source array:")
            Console.WriteLine()
            Console.WriteLine(New With {.Method = "ResizeArray1",.Time = watch.Elapsed.ToString()})
        End If

        'Resize array #2

        watch = Stopwatch.StartNew()

        For i As Int32 = 1 To iterations
            For n As Int32 = 1 To maxSize
                a = CreateArray(Of String)(0)
                ResizeArray2(a,n)
            Next
        Next

        watch.Stop()

        If (Not warmUp) Then
            Console.WriteLine(New With {.Method = "ResizeArray2",.Time = watch.Elapsed.ToString()})
        End If

        'BY: GROWING SOURCE ARRAY -------------------------------

        'Resize array #1

        watch = Stopwatch.StartNew()
        a = Program.CreateArray(Of String)(0)

        For i As Int32 = 1 To iterations
            For n As Int32 = 1 To maxSize
                Program.ResizeArray1(a,n)
            Next
        Next

        watch.Stop()

        If (Not warmUp) Then
            Console.WriteLine()
            Console.WriteLine("Growing source array:")
            Console.WriteLine()
            Console.WriteLine(New With {.Method = "ResizeArray1",.Time = watch.Elapsed.ToString()})
        End If

        'Resize array #2

        watch = Stopwatch.StartNew()
        a = Program.CreateArray(Of String)(0)

        For i As Int32 = 1 To iterations
            For n As Int32 = 1 To maxSize
                Program.ResizeArray2(a,.Time = watch.Elapsed.ToString()})
        End If

    End Sub

    Private Function CreateArray(Of T)(size As Int32) As T()
        Return New T(size - 1) {}
    End Function

    Private Sub ResizeArray1(Of T)(ByRef a As T(),size As Int32)
        ReDim Preserve a(size - 1)
    End Sub

    Private Sub ResizeArray2(Of T)(ByRef a As T(),size As Int32)
        Array.Resize(a,size)
    End Sub

End Module

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读