循环排序列表 - 为什么这样更快?
以下示例中的 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
为什么前两个代码块慢得多?
List1 in the following example is a SortedList(Of MyClass) and contains 251 members.
The first two codeblocks execute in 15.5 seconds.
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
This one executes in 5.6 seconds.
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
Why are the first two codeblocks so much slower?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
SortedList 通过实现 IComparer 来扩展 Collection,以提供排序功能。在内部,它实现了 2 个数组来存储列表的元素 - 一个用于键的数组,一个用于值的数组。 .NET 数组针对快速有序和快速随机访问进行了优化。
我怀疑前两个语句速度慢的原因是 SortedList 中的 foreach 语句是 Enumerator 的包装器。调用 foreach 将查询枚举器,调用 MoveNext 和 Current。此外,在遍历列表时,遍历通用列表可能会涉及装箱和拆箱,并且可能会产生通常通过索引访问不会获得的性能开销。
The SortedList extends a Collection by implementing IComparer to provide the sort functionality. Internally, it implements 2 arrays to store the elements of the list - one array for the key and one for the values. The .NET Array is optimised for fast in-order and fast random access.
My suspicion why the first 2 are slow is because the foreach statement in a SortedList is a wrapper around the Enumerator. Calling foreach will query for the enumerator, call MoveNext and Current. In addition, going though the generic list can potentially involve boxing and unboxing as you traverse the list, and can create performance overhead that you would not normally get by accessing by Index.
我试图四处寻找一些关于
For Each
行为的文档,但我找不到它。我的理论是,使用 For Each 语句将列表中的对象复制到内存中的另一个位置,然后在循环的每次迭代结束时将其复制回列表中。
另一种可能性是,它在每次迭代开始时调用构造函数,然后解构并再次调用构造函数以重置下一次迭代。
我不确定这些理论中的任何一个,但 3 和(1 或 2)之间的主要区别是缺少
For Each
。编辑:在 MSDN 找到一些文档。
这是摘录:
因此,总体而言,听起来
For Each
更加“受管理”,并且花费了大量开销来确保一切都匹配。结果,速度变慢了。I tried to look around for some documentation on exactly how
For Each
behaves, but I couldn't find it.My theory is that using the
For Each
statements copies the object in the list to another spot in memory and then copies it back into the list when each iteration of the loop ends.Another possibility is that it calls the constructor at the start of every iteration and then deconstructs and calls the constructor again to reset for the next iteration.
I'm not sure on either of these theories, but the major difference between 3 and (1 or 2) is the lack of
For Each
.EDIT: Found some documentation at MSDN.
Here's an excerpt:
So overall it sounds like
For Each
is more "managed" and does a lot of overhead to make sure everything matches up. As a result, it's slower.我认为由于固定的循环范围,编译器可以更好地优化块 3。在块 1 和 2 中,编译器在评估 List 之前不会知道循环的上限是什么,从而使其变慢。
I would think the compiler can better optimize block 3 because of the fixed loop range. In blocks one and 2 the compiler won't know what the upper limit of the loop is until it evaluates the List thus making it slower.
我的随机猜测:
List1 包含约 750 个元素(而不仅仅是 250 个)。
第三种情况更快,因为它不会迭代 List1 具有的每个元素。
My random guess:
List1 contains ~750 elements (and not just 250).
Your third case is faster, because it does not iterate over each element which List1 has.