Implementacja pętli List.Contains () pojawia się szybciej niż wbudowana pętla. To jest? Jeśli tak, to dlaczego?

(To pytanie wynika z dyskusji, która rozpoczęła się tutaj)

Porównywałem czasy szukaniatrue wartość w aList<bool> za pomocąList.Contains() z tymi dla pętli ręcznie zwijanej.

Widzę różne wyniki od tych zgłaszanych przez innych ludzi. Wypróbowałem go w kilku systemach, a pętla wydaje się szybsza od 2 do 3,5 razy na wszystkich systemach, na których próbowałem. Systemy te obejmują 5-letnie laptopy z systemem XP z .Net 4 do najnowszych komputerów z systemem Windows 8 i .Net 4.5.

Inni ludzie podają różne wyniki, a mianowicie takieList.Contains() jest mniej więcej z taką samą prędkością lub nieco szybciej niż pętla.

Oto mój kod testowy.

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);
        }
    }
}

Aby przetestować ten kod, powinieneś skompilować go jako kompilację RELEASE x86 i uruchomić go zna zewnątrz debugger.

Oto moje wyniki z mojego komputera z systemem Windows 8 x64 korzystającego z platformy .Net 4.5 (chociaż uzyskuję podobne wyniki z .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()

Jak widać, pętla zajmuje około 1/3 czasu w moim systemie.

Teraz, jeśli użyjemyResharper przyjrzeć się realizacjiList.Contains() To wygląda tak:

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;
}

Chociaż używaComparer.Equals() (co powinno sprawić, że będzie wolniejszy niż pętla), używa również prywatnego_items[] array bezpośrednio, co pozwala uniknąć sprawdzania zakresu indeksu, który będzie używany do implementacji mojej pętli.

Mam trzy pytania:

Czy ktoś inny może powtórzyć wyniki, które widzę? (Pamiętaj, aby uruchomić kompilację wydania poza debuggerem).Jeśli tak, czy ktoś może wyjaśnić, jak moja pętla może być o wiele szybsza niżList.Contains()?Jeśli nie, czy ktoś może wyjaśnić, dlaczego moja pętla jest szybsza?

Nie chodzi mi tylko o interesy akademickie, ponieważ piszę kod, który działa z dużą ilością danych liczbowych i który musi być tak szybki, jak to możliwe, i to jest coś, o czym muszę wiedzieć. (Uwaga: Tak, profiluję rzeczy i próbuję optymalizować rzeczy, które wymagają optymalizacji ... Wiem o problemach z przedwczesną optymalizacją.)

[EDYTOWAĆ]

Wydaje mi się, że może to być związane z procesorem. Wszystkie systemy, na których próbowałem, mają procesory Intela, aczkolwiek bardzo różne modele, od Quad Core przy 3,8 GHz do pojedynczego rdzenia Pentium M przy 1,6 GHz ...

Dla tych, którzy widzą, że pętla działa wolniej, używasz procesorów Intel?

questionAnswers(2)

yourAnswerToTheQuestion