的List1在下面的例子是一个排序列表(中MyClass的),并包含251名成员。

<强>前两个码块执行15.5秒。

 For cnt As Integer = 1 To 1000000
        For Each TempDE In List1
            Dim F As String = TempDE.Key
            TempDE.Value.x1 = 444
        Next
    Next

    For cnt As Integer = 1 To 1000000
        For Each TempDE As KeyValuePair(Of String, phatob) In List2
            Dim F As String = TempDE.Key
            TempDE.Value.x1 = 444
        Next
    Next

:该一个在5.6秒执行。

    For cnt As Integer = 0 To 999999
        For cnt2 As Integer = 0 To 250
            Dim F As String = List1.Keys(cnt2)
            List1.Values(cnt2).x1 = 444
        Next

    Next

<强>为什么前两个码块如此慢得多吗

有帮助吗?

解决方案

在排序列表通过实施的IComparer以提供排序的功能延伸的集合。在内部,它实现2个数组来存储列表的元素 - 一个阵列的密钥和一个为值。在.NET阵列对于快速有序和快速随机访问进行了优化。

我怀疑为什么第2慢是因为在排序列表foreach语句是围绕枚举的包装。调用的foreach将查询枚举器,调用的MoveNext和电流。此外,虽然去的泛型列表有可能涉及到装箱和拆箱为您遍历列表,并且可以创建性能开销,你通常不会通过索引访问得到。

其他提示

我试着到处寻找有关For Each究竟是如何表现的一些文档,但我找不到它。

我的理论是使用For Each语句拷贝在列表中的对象在内存中的另一个点,然后将其放回列表当循环的每次迭代结束。

拷贝

另一种可能性是,它调用在每次迭代开始时的构造函数,然后解构和再次调用构造重置为下一次迭代。

我不知道在任这些理论,但3之间的主要区别(1或2)是缺乏For Each的。

编辑:实测值在 MSDN 一些文档

下面是一个摘录:

  

当的执行对于每个...下一个循环开始时,Visual Basic验证组是指一个有效集合对象。如果不是,它抛出一个异常。否则,它会调用MoveNext方法和枚举对象返回的第一个元素的当前属性。如果MoveNext的指示不存在下一个元素,也就是说,如果集合为空,那么For Each循环终止且控制传给下面的下一条语句声明。否则,Visual Basic中设置元素的第一要素和运行语句块。

所以,总体来说,它听起来就像For Each是更多的“管理”,并做了很多开销,以确保一切相匹配。其结果是,它是较慢的。

我认为编译器可以更好地优化,因为固定环范围块3。在块中的一个和2编译器将不知道循环的上限是什么,直到它计算的列表从而使其慢。

我的随机猜测: List1中含有〜750个元素(不只是250)。 您的第三种情况是更快,因为它不会在其上具有的List1的每个元素进行迭代。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top