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?