Loop implementação de List.Contains () aparece mais rápido que o interno. É isso? Se sim, porque?
(Esta questão surge de uma discussão que começou aqui)
Eu estava comparando os horários para procurar umtrue
valor numList<bool>
usandoList.Contains()
com aqueles para um loop enrolado à mão.
Estou vendo resultados diferentes daqueles reportados por outras pessoas. Eu tentei em vários sistemas, eo loop parece mais rápido entre 2 e 3,5 vezes em todos os sistemas que eu tentei. Esses sistemas variam de laptops de 5 anos que executam o XP com o .Net 4 para PCs recentes que executam o Windows 8 e o .Net 4.5.
Outras pessoas estão relatando resultados diferentes, ou seja, queList.Contains()
tem aproximadamente a mesma velocidade ou um pouco mais rápido que o loop.
Aqui está meu código de teste.
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);
}
}
}
Para testar esse código, você deve compilá-lo como uma compilação RELEASE x86 e executá-lolado de fora o depurador.
Aqui estão os meus resultados do meu PC com Windows 8 x64 usando o framework .Net 4.5 (embora eu tenha resultados semelhantes com o .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()
Como você pode ver, o loop leva em torno de 1/3 do tempo no meu sistema.
Agora, se usarmosResharper
olhar para a implementação deList.Contains()
Se parece com isso:
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;
}
Embora esteja usandoComparer.Equals()
(o que deve torná-lo mais lento que o loop) ele também está usando o_items[]
array diretamente, o que evita a verificação do intervalo do índice que será usado para a implementação do meu loop.
Eu tenho três perguntas:
Alguém mais pode replicar os resultados que estou vendo? (Lembre-se de executar uma compilação de release fora do depurador).Se assim for, alguém pode explicar como o meu loop pode ser muito mais rápido do queList.Contains()
?Se não, alguém pode explicar porque eu estou vendo meu loop para ser mais rápido?Isso não é apenas de interesse acadêmico para mim, já que escrevo códigos que funcionam com grandes quantidades de dados numéricos e que precisam ser o mais rápido possível, e esse é o tipo de coisa que eu preciso saber. (Nota: Sim, faço o perfil das coisas e apenas tento otimizar as coisas que precisam ser otimizadas ... Eu sei sobre os problemas de otimização prematura.)
[EDITAR]
Ocorre-me que isso poderia estar relacionado ao processador. Todos os sistemas que experimentei possuem processadores Intel, embora com modelos muito diferentes, desde o Quad Core a 3.8GHz até um Pentium M single core a 1.6GHz ...
Para aqueles que vêem o loop rodando mais devagar, você está executando processadores Intel?