循环执行List.Contains的()出现的速度比内置的之一。是吗?如果是这样,为什么? [英] Loop implementation of List.Contains() appears faster than the built-in one. Is it? If so, why?
问题描述
(这个问题是从这里开始讨论)
我是比较时序为寻找真正
在列表与LT值;与为手卷
使用 List.Contains)(
;布尔>循环。
I was comparing the timings for looking for a true
value in a List<bool>
using List.Contains()
with those for a hand-rolled loop.
我看到那些其他人不同的结果。我已经尝试过了几个系统,循环似乎更快,由2和3.5倍之间的所有我已经试过它的系统。这些系统的范围从在.NET 4中运行XP到运行Windows 8和.NET 4.5最近的PC 5岁的笔记本电脑。
I am seeing different results from those reported by other people. I have tried it on several systems, and the loop seems faster by between 2 and 3.5 times on all the systems I've tried it on. These systems range from 5-year-old laptops running XP with .Net 4 to recent PCs running Windows 8 and .Net 4.5.
其他人都报告不同的结果,即 List.Contains()
是差不多的速度,或比,循环速度稍快。
Other people are reporting different results, namely that List.Contains()
is about the same speed as, or slightly faster than, the loop.
下面是我的测试代码。
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main()
{
int size = 10000000;
int count = 10;
List<bool> data = new List<bool>(size);
for (int i = 0; i < size; ++i)
data.Add(false);
var sw = new Stopwatch();
for (int trial = 0; trial < 5; ++trial)
{
sw.Restart();
for (int i = 0; i < count; ++i)
TestViaLoop(data);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds + " TestViaLoop()");
sw.Restart();
for (int i = 0; i < count; ++i)
TestViaListContains(data);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds + " TestViaListContains()");
Console.WriteLine();
}
}
static bool TestViaLoop(List<bool> data)
{
for (int i = 0; i < data.Count; ++i)
if (data[i])
return true;
return false;
}
static bool TestViaListContains(List<bool> data)
{
return data.Contains(true);
}
}
}
要测试此代码,您从我的Windows 8的x64 PC我的结果使用应该编译它作为一个x86发布版本,并从的 的调试器外运行它。
To test this code, you should compile it as an x86 RELEASE build, and run it from outside the debugger.
下面在.NET 4.5框架(虽然我得到在.NET 4中类似的结果):
Here are my results from my Windows 8 x64 PC using the .Net 4.5 framework (although I get similar results with .Net 4):
Times are in milliseconds
126 TestViaLoop()
441 TestViaListContains()
122 TestViaLoop()
428 TestViaListContains()
131 TestViaLoop()
431 TestViaListContains()
138 TestViaLoop()
426 TestViaListContains()
122 TestViaLoop()
439 TestViaListContains()
正如你所看到的,循环需要大约1/3的时候我的系统上。
As you can see, the loop takes around 1/3 the time on my system.
现在,如果我们使用 ReSharper的
来看看 List.Contains的实现()
它看起来是这样的:
Now if we use Resharper
to look at the implementation of List.Contains()
it looks like this:
bool Contains(T item)
{
if (item == null)
{
for (int j = 0x0; j < this._size; j++)
{
if (this._items[j] == null)
{
return true;
}
}
return false;
}
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0x0; i < this._size; i++)
{
if (comparer.Equals(this._items[i], item))
{
return true;
}
}
return false;
}
虽然它使用 Comparer.Equals()
(这应该使它比循环更慢),这也直接使用专用 _items []
阵列,避免了指数范围检查,这将是。被用于我的循环执行
Although it is using Comparer.Equals()
(which should make it slower than the loop) it is also using the private _items[]
array directly, which avoids the index range check which will be being used for my loop implementation.
我有三个问题:
- 可以别人复制我看到的结果? (记住要运行调试器之外的发布版本。)
- 如果是这样,任何人都可以解释我的循环怎么可以这么比
List.Contains快得多()
? - 如果没有,任何人都可以解释为什么我看到我的循环要快一些?
这不仅仅是学术上的兴趣给我的,因为我写的,随着大量数字数据和需要被尽可能快的运行的代码,这是诸如此类的事情,我需要知道关于。 (注:是的,我个人资料的东西,只能尽量优化的东西,需要优化......我知道过早优化问题)
This is not just of academic interest to me, since I write code that works with large amounts of numeric data and which needs to be as fast as possible, and this is the sort of thing I need to know about. (Note: Yes, I profile things and only try to optimise stuff that needs to be optimised... I know about the problems of premature optimisation.)
它发生,我认为这可能是处理器相关的。所有我试过它的系统有英特尔处理器,虽然很不同的型号,从四核3.8GHz的处到奔腾M单核1.6 GHz的...
It occurs to me that this could be processor related. All the systems I've tried it on have Intel processors, albeit very different models ranging from Quad Core at 3.8GHz to a Pentium M single core at 1.6 GHz...
对于那些你们谁看到了循环运行的速度较慢,你在运行英特尔处理器?
For those of you who see the loop running slower, are you running Intel processors?
推荐答案
它采用GenericEqualityComparer,如果我们看一下在equals方法的实现看起来是这样的:
It uses GenericEqualityComparer, if we look at the implementation of the Equals method is looks like this:
public override bool Equals(T x, T y)
{
if ((object) x != null)
{
if ((object) y != null)
return x.Equals(y);
else
return false;
}
else
return (object) y == null;
}
当它检查对象是否不等于空,这让拳击他们你得到两个装箱操作。这IL代码显示它的外观:
When it checks whether the objects are not equal to null, it makes boxing them and you get two boxing operation. This IL-code shows how it looks:
IL_0002: box !T
IL_0007: ldnull
IL_0008: ceq
修改通过280Z28:作为相同的方法CIL是在.NET 4.5略有不同。
Edit by 280Z28: The CIL for the same method is slightly different in .NET 4.5.
public override bool Equals(T x, T y)
{
if (x != null)
return ((y != null) && x.Equals(y));
if (y != null)
return false;
return true;
}
下面是IL。对于任何人看着反射,注意 brfalse.s
和 brnull.s
是相同的指令。
Here is the IL. For anyone looking at Reflector, note that brfalse.s
and brnull.s
are the same instruction.
L_0000: ldarg.1
L_0001: box !T
L_0006: brnull.s L_0021
...
基准JIT编译器不优化掉的暗箱操作,但我还没有NGEN检查或优化编译器,看看他们做的。
The baseline JIT compiler does not optimize away the box operation, but I have not checked with NGen or the optimizing compiler to see if they do.
这篇关于循环执行List.Contains的()出现的速度比内置的之一。是吗?如果是这样,为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!