Digamos que você precise ter uma lista / matriz de números inteiros que você precisa repetir com frequência, e eu quero dizer com muita frequência. Os motivos podem variar, mas digamos que esteja no coração do loop mais interno de um processamento de alto volume.
Em geral, optamos pelo uso de Listas (Lista) devido à sua flexibilidade em tamanho. Além disso, a documentação do msdn afirma que as Lists usam uma matriz internamente e devem ter o mesmo desempenho rápido (uma rápida olhada no Reflector confirma isso). No entanto, há alguma sobrecarga envolvida.
Alguém realmente mediu isso? iterar 6 milhões de vezes através de uma lista levaria o mesmo tempo que uma matriz faria?
T[]
vs.List<T>
pode fazer uma grande diferença de desempenho. Acabei de otimizar um aplicativo intensivo de loop extremamente (aninhado) para passar de listas para matrizes no .NET 4.0. Eu estava esperando talvez 5% a 10% de melhoria, mas obtive mais de 40% de aceleração! Não há outras alterações além de mover diretamente da lista para a matriz. Todas as enumerações foram feitas comforeach
instruções. Com base na resposta de Marc Gravell, parece queforeach
comList<T>
é particularmente ruim.Respostas:
Muito fácil de medir ...
Em um pequeno número de código de processamento em circuito fechado, onde eu sei que o comprimento é fixo, eu uso matrizes para esse pequeno pouquinho extra de otimização; matrizes podem ser marginalmente mais rápidas se você usar o indexador / para formulário - mas o IIRC acredita que depende do tipo de dados na matriz. Mas, a menos que você precise otimizar, mantenha-o simples e use
List<T>
etc.Obviamente, isso só se aplica se você estiver lendo todos os dados; um dicionário seria mais rápido para pesquisas baseadas em chaves.
Aqui estão meus resultados usando "int" (o segundo número é uma soma de verificação para verificar se todos fizeram o mesmo trabalho):
(editado para corrigir o erro)
com base no equipamento de teste:
fonte
Resumo:
A matriz precisa usar:
A lista precisa usar:
O LinkedList precisa usar:
Mais detalhes:
Muito mais detalhes:
https://stackoverflow.com/a/29263914/4423545
fonte
Eu acho que o desempenho será bem parecido. A sobrecarga envolvida ao usar uma lista versus uma matriz é IMHO quando você adiciona itens à lista e quando a lista precisa aumentar o tamanho da matriz que ela está usando internamente, quando a capacidade da matriz é atingida.
Suponha que você tenha uma lista com capacidade de 10; a lista aumentará sua capacidade assim que você desejar adicionar o 11º elemento. Você pode diminuir o impacto no desempenho, inicializando a Capacidade da lista com o número de itens que ela conterá.
Mas, para descobrir se a iteração sobre uma lista é tão rápida quanto a iteração sobre uma matriz, por que você não a avalia?
No meu sistema; a iteração na matriz levou 33 ms; iterar sobre a lista levou 66 ms.
Para ser sincero, não esperava que a variação fosse tão grande. Então, eu coloquei minha iteração em um loop: agora, eu executo as duas iterações 1000 vezes. Os resultados são:
Agora, a variação não é mais tão grande, mas ainda assim ...
Portanto, iniciei o .NET Reflector e o getter do indexador da classe List se parece com o seguinte:
Como você pode ver, quando você usa o indexador da lista, a lista executa uma verificação se você não está saindo dos limites da matriz interna. Essa verificação adicional tem um custo.
fonte
se você está obtendo um único valor de qualquer um (não em um loop), os dois fazem a verificação de limites (você lembra do código gerenciado); é apenas a lista que faz isso duas vezes. Veja as notas mais tarde para saber por que isso provavelmente não é grande coisa.
Se você estiver usando o seu próprio para (int int i = 0; i <x. [Comprimento / Contagem]; i ++), a diferença principal é a seguinte:
Se você estiver usando o foreach, a principal diferença é a seguinte:
A verificação de limites geralmente não é grande coisa (especialmente se você estiver em uma CPU com uma previsão profunda de canal e ramificação - a norma para a maioria dos dias de hoje), mas apenas seu próprio perfil pode dizer se isso é um problema. Se você estiver em partes do código em que está evitando alocações de heap (bons exemplos são bibliotecas ou implementações de código de hash), garanta que a variável seja digitada, pois List not IList evitará essa armadilha. Como sempre perfil, se isso importa.
fonte
[ Veja também esta pergunta ]
Modifiquei a resposta de Marc para usar números aleatórios reais e, na verdade, fazer o mesmo trabalho em todos os casos.
Resultados:
Compilado como versão no VS 2008 SP1. Executando sem depuração em um [email protected], .NET 3.5 SP1.
Código:
fonte
As medidas são boas, mas você obterá resultados significativamente diferentes, dependendo do que estiver fazendo exatamente no seu loop interno. Meça sua própria situação. Se você estiver usando multiencadeamento, isso por si só é uma atividade não trivial.
fonte
De fato, se você executar alguns cálculos complexos dentro do loop, o desempenho do indexador de matriz versus o indexador de lista pode ser tão marginalmente pequeno que, eventualmente, isso não importa.
fonte
Aqui está um que usa Dictionaries, IEnumerable:
fonte
Não tente adicionar capacidade aumentando o número de elementos.
atuação
fonte
Eu estava preocupado que os Benchmarks publicados em outras respostas ainda deixassem espaço para o compilador otimizar, eliminar ou mesclar loops, então escrevi um que:
O resultado é que uma matriz direta tem desempenho 250% melhor que o acesso a uma matriz envolvida em um IList:
Aqui está o código:
fonte
Como a List <> usa matrizes internamente, o desempenho básico deve ser o mesmo. Por duas razões, a lista pode ser um pouco mais lenta:
Para verificar se isso faz alguma diferença para você, provavelmente é melhor ajustar as funções de tempo publicadas para uma lista do tamanho que você planeja usar e ver como são os resultados para o seu caso especial.
fonte
Como eu tinha uma pergunta semelhante, isso me deu um começo rápido.
Minha pergunta é um pouco mais específica, 'qual é o método mais rápido para uma implementação de matriz reflexiva'
Os testes feitos por Marc Gravell mostram muito, mas não exatamente o tempo de acesso. Seu tempo inclui também o loop sobre as listas e matrizes. Como também criei um terceiro método que queria testar, um 'Dicionário', apenas para comparar, estendi o código do teste hist.
Primeiramente, faço um teste usando uma constante, o que me dá um certo tempo, incluindo o loop. Esse é um momento "vazio", excluindo o acesso real. Então eu faço um teste para acessar a estrutura do assunto, isso me dá um tempo, um loop e o acesso real 'overhead included'.
A diferença entre o tempo 'bare' e o tempo 'overhead indluded' me dá uma indicação do tempo de 'acesso à estrutura'.
Mas quão preciso é esse momento? Durante o teste, as janelas farão algum tempo cortando shure. Não tenho informações sobre o tempo de redução, mas presumo que ele seja distribuído igualmente durante o teste e na ordem de dezenas de ms, o que significa que a precisão do tempo deve ser da ordem de +/- 100 ms ou mais. Uma estimativa um pouco grosseira? De qualquer forma, uma fonte de um erro sistemático de medição.
Além disso, os testes foram feitos no modo 'Debug' sem otimização. Caso contrário, o compilador pode alterar o código de teste real.
Portanto, obtenho dois resultados, um para uma constante, marcado '(c)', e outro para o acesso marcado como '(n)' e a diferença 'dt' me diz quanto tempo leva o acesso real.
E estes são os resultados:
Com melhores estimativas dos erros de temporização (como remover o erro sistemático de medição devido à redução do tempo?), Mais poderia ser dito sobre os resultados.
Parece que List / foreach tem o acesso mais rápido, mas a sobrecarga está acabando.
A diferença entre List / for e List / foreach é estranha. Talvez algum dinheiro esteja envolvido?
Além disso, para acessar uma matriz, não importa se você usa um
for
loop ou umforeach
loop. Os resultados de tempo e sua precisão tornam os resultados 'comparáveis'.Usar um dicionário é de longe o mais lento, só o considerei, porque no lado esquerdo (o indexador) tenho uma lista esparsa de números inteiros e não um intervalo, como é usado nesses testes.
Aqui está o código de teste modificado.
fonte
Em alguns breves testes, achei uma combinação dos dois melhor no que eu chamaria de matemática razoavelmente intensiva:
Tipo:
List<double[]>
Tipo:
List<List<double>>
Tipo:
double[rows * columns]
Executando o código:
Eu gostaria que tivéssemos algumas classes de matriz acelerada de hardware de alto nível, como a equipe do .NET, que fizeram com a
System.Numerics.Vectors
classe!C # poderia ser a melhor linguagem ML com um pouco mais de trabalho nessa área!
fonte