循环执行List.Contains的()出现的速度比内置的之一。是吗?如果是这样,为什么? [英] Loop implementation of List.Contains() appears faster than the built-in one. Is it? If so, why?

查看:929
本文介绍了循环执行List.Contains的()出现的速度比内置的之一。是吗?如果是这样,为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是从这里开始讨论)

我是比较时序为寻找真正列表与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.

我有三个问题:


  1. 可以别人复制我​​看到的结果? (记住要运行调试器之外的发布版本。)

  2. 如果是这样,任何人都可以解释我的循环怎么可以这么比 List.Contains快得多()

  3. 如果没有,任何人都可以解释为什么我看到我的循环要快一些?

这不仅仅是学术上的兴趣给我的,因为我写的,随着大量数字数据和需要被尽可能快的运行的代码,这是诸如此类的事情,我需要知道关于。 (注:是的,我个人资料的东西,只能尽量优化的东西,需要优化......我知道过早优化问题)

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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆