【问题标题】:Cycling through a SortedList - Why is this faster?在 SortedList 中循环 - 为什么这样更快?
【发布时间】:2009-11-02 01:01:11
【问题描述】:

以下示例中的 List1 是一个 SortedList(Of 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

为什么前两个代码块这么慢?

【问题讨论】:

  • 不确定,但 For Each 循环的开销可能比整数上的 For 循环更大。因此,第二行可能负责加速?我真的不知道。
  • 前两个循环需要 15.5 秒,还是每个循环?
  • 运行我自己的一些测试后,您确定列表有 251 个元素吗?以及为什么第二个示例使用 List2?

标签: .net vb.net containers sortedlist


【解决方案1】:

SortedList 通过实现 IComparer 来扩展 Collection 以提供排序功能。在内部,它实现了 2 个数组来存储列表的元素——一个数组用于键,一个数组用于值。 .NET 数组针对快速有序和快速随机访问进行了优化。

我怀疑为什么前 2 个很慢是因为 SortedList 中的 foreach 语句是 Enumerator 的包装器。调用 foreach 将查询枚举数,调用 MoveNext 和 Current。此外,遍历通用列表可能会在您遍历列表时涉及装箱和拆箱,并且可能会产生通常通过索引访问不会获得的性能开销。

【讨论】:

  • 这是我试图得到答案的更好版本:)
【解决方案2】:

我试图四处寻找有关For Each 行为方式的文档,但找不到。

我的理论是使用For Each 语句将列表中的对象复制到内存中的另一个位置,然后在循环的每次迭代结束时将其复制回列表中。

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

我不确定这两种理论,但 3 和(1 或 2)之间的主要区别在于缺少 For Each。

编辑:在MSDN 找到一些文档。

摘录如下:

当 For Each...Next 循环开始执行时,Visual Basic 会验证该组是否引用了一个有效的集合对象。如果不是,它会抛出异常。否则,它调用 MoveNext 方法和枚举器对象的 Current 属性以返回第一个元素。如果 MoveNext 指示没有下一个元素,即如果集合为空,则 For Each 循环终止并且控制传递到 Next 语句之后的语句。否则,Visual Basic 将 element 设置为第一个元素并运行语句块。

所以总体而言,For Each 听起来更“受管理”,并且会花费大量开销来确保所有内容都匹配。结果,它变慢了。

【讨论】:

    【解决方案3】:

    我认为由于固定的循环范围,编译器可以更好地优化块 3。在块 1 和 2 中,编译器在计算 List 之前不会知道循环的上限是多少,从而使其变慢。

    【讨论】:

    • 绝对是一个有效的点。我认为它有所贡献,但可能不是整个问题。
    【解决方案4】:

    我的随机猜测: List1 包含约 750 个元素(而不仅仅是 250 个)。 您的第三种情况更快,因为它不会遍历 List1 拥有的每个元素。

    【讨论】:

    • 我现在倾向于将此作为正确答案,因为我自己的测试表明 For Each 与常规迭代的速度大致相同。为了进一步支持这一说法,您正在迭代 251 个元素(0 到 250)而没有错误,因此该列表不包含您认为的元素数量。
    猜你喜欢
    • 2020-12-25
    • 1970-01-01
    • 2020-05-11
    • 2016-05-26
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多