Desempenho da atribuição de valores ao array

Otimização de código é dito aqui em SO que o perfil é o primeiro passo para otimizar o javascript e os motores sugeridos são profilers do Chrome e Firefox. O problema com eles é que eles dizem de alguma maneira estranha o tempo que cada função é executada, mas eu não tenho nenhum bom entendimento deles. A maneira mais útil seria que o profiler diria quantas vezes cada linha é executada e, se possível, também o tempo gasto em cada linha. Desta forma, seria possível ver os gargalos estritamente. Mas antes que essa ferramenta seja implementada / encontrada, temos duas opções:

1) faça a própria calculadora que conta o tempo e quantas vezes determinado bloco de código ou linha é executado 2) aprenda a entender quais são métodos lentos e quais não são

Para a opção 2jsperf.com é de grande ajuda. Eu tentei aprender a otimizar matrizes e fiz um teste de velocidade emJSPERF.COM. A imagem a seguir mostra os resultados em cinco navegadores principais e encontrou alguns gargalos que eu não conhecia anteriormente.

As principais conclusões foram:

1) Atribuir valores a matrizes é significativamente mais lento do que atribuir a variáveis ​​normais, apesar de qual método é usado para atribuição.

2) A pré-inicialização e / ou pré-preenchimento da matriz antes dos ciclos críticos de desempenho podem melhorar significativamente a velocidade

3) As funções trigonométricas de matemática não são tão lentas quando comparadas com valores empurrados em matrizes (!)

Aqui estão as explicações de todos os testes:

1. non_array (100%):

As variáveis ​​receberam um valor pré-definido desta forma:

var non_array_0=0;
var non_array_1=0;
var non_array_2=0;
...

e na região cronometrada foram chamados assim:

non_array_0=0;
non_array_1=1;
non_array_2=2;
non_array_3=3;
non_array_4=4;
non_array_5=5;
non_array_6=6;
non_array_7=7;
non_array_8=8;
non_array_9=9;

O acima é uma variável do tipo matriz, mas parece não haver nenhuma maneira de iterar ou referir-se a essas variáveis ​​de outra forma como oppocite to array. Ou está lá?

Nada neste teste é mais rápido do que atribuir um número à variável.

2. non_array_non_pre (83,78%)

Exatamente o mesmo que o teste 1, mas as variáveis ​​não foram pré-inicializadas nem pré-preenchidas. A velocidade é de 83,78% da velocidade do teste 1. Em todos os navegadores testados, a velocidade das variáveis ​​pré-preenchidas foi mais rápida do que as não preenchidas.Portanto, inicialize (e possivelmente preencha) variáveis ​​fora de qualquer loop crítico de velocidade.

O código de teste está aqui:

var non_array_non_pre_0=0;
var non_array_non_pre_1=0;
var non_array_non_pre_2=0;
var non_array_non_pre_3=0;
var non_array_non_pre_4=0;
var non_array_non_pre_5=0;
var non_array_non_pre_6=0;
var non_array_non_pre_7=0;
var non_array_non_pre_8=0;
var non_array_non_pre_9=0;

3. pre_filled_array (19.96%):

Arrays são maus! Quando descartamos variáveis ​​normais (test1 e test2) e colocamos matrizes na imagem, a velocidade diminui significativamente.Embora façamos todas as otimizações (preinitialize e prefill arrays) e, em seguida, atribua valores diretamente sem loop ou push, a velocidade diminui para 19,96%. Isso é muito triste e eu realmente não entendo porque isso ocorre. Este foi um dos principais choques para mim neste teste. Matrizes são tão importantes, e eu não encontrei uma maneira de fazer muitas coisas sem matrizes.

Os dados do teste estão aqui:

pre_filled_array[0]=0;
pre_filled_array[1]=1;
pre_filled_array[2]=2;
pre_filled_array[3]=3;
pre_filled_array[4]=4;
pre_filled_array[5]=5;
pre_filled_array[6]=6;
pre_filled_array[7]=7;
pre_filled_array[8]=8;
pre_filled_array[9]=9;

4. non_pre_filled_array (8.34%):

Este é o mesmo teste que 3, mas os membros da matriz não são pré-inicializados nem pré-preenchidos, apenas a otimização era inicializar a matriz de antemão:var non_pre_filled_array=[];

A velocidade diminui 58,23% em relação ao teste pré-inicializado 3.Então, preinitializing e / ou pré-preenchimento de matriz sobre o dobro da velocidade.

O código de teste está aqui:

non_pre_filled_array[0]=0;
non_pre_filled_array[1]=1;
non_pre_filled_array[2]=2;
non_pre_filled_array[3]=3;
non_pre_filled_array[4]=4;
non_pre_filled_array[5]=5;
non_pre_filled_array[6]=6;
non_pre_filled_array[7]=7;
non_pre_filled_array[8]=8;
non_pre_filled_array[9]=9;

5. pre_filled_array [i] (7.10%):

Então para os laços. Método de loop mais rápido neste teste. A matriz foi pré-inicializada e pré-preenchida.

A queda de velocidade em comparação com a versão inline (teste 3) é de 64,44%. Esta é uma diferença tão notável que eu diria, não faça um loop se não for necessário. Se o tamanho do array for pequeno (não sei quão pequeno, ele deve ser testado separadamente), é mais sábio usar atribuições inline em vez de looping.

E como a queda de velocidade é tão grande e nós realmente precisamos de loops, é sensato encontrarmelhor método de looping (por exemplo.while(i--)).

O código de teste está aqui:

for(var i=0;i<10;i++)
{
  pre_filled_array[i]=i;
}

6. non_pre_filled_array [i] (5,26%):

Se não pré-inicializarmos e preenchermos o array, a velocidade diminuirá 25,96%. Mais uma vez, a pré-inicialização e / ou pré-preenchimento antes da velocidade dos loops críticos é sensata.

O código está aqui:

for(var i=0;i<10;i++) 
{
  non_pre_filled_array[i]=i;
}

7. Cálculos matemáticos (1,17%):

Cada teste tem que ser algum ponto de referência. Funções matemáticas são consideradas lentas. O teste consistiu em dez cálculos matemáticos "pesados", mas agora vem a outra coisa que me impressionou neste teste. Olhe para a velocidade de 8 e 9, onde pressionamos dez números inteiros para agrupar em loop. Calcular essas 10 funções matemáticas é mais de 30% mais rápido do que empurrar dez inteiros para o array em loop. Então, pode ser que seja mais fácil converter alguns arranjos de matriz para não-arrays pré-inicializados e manter esses trigonométricos. É claro que, se houver centenas ou milhares de cálculos por quadro, é aconselhável usar, por exemplo. sqrt em vez de sin / cos / tan e usar as distâncias de táxi para comparações de distância eângulos de diamante (t-radianos) para comparações de ângulosmas o principal gargalo pode estar em outro lugar: o loop é mais lento que o inline, o push é mais lento do que usar a atribuição direta com preinitilização e / ou pré-preenchimento, lógica de código, algoritmos de desenho e acesso DOM podem ser lentos. Tudo não pode ser otimizado em JavaScript (temos que ver algo na tela!), Mas tudo o que é fácil e significativo que podemos fazer, é aconselhável fazer. Alguém aqui no SO disse que o código é para humanos e que o código legível é mais essencial do que o código rápido, porque o custo de manutenção é o maior custo. Este é um ponto de vista econômico, mas descobri que a otimização de código pode obter os dois: elegância, legibilidade e desempenho. E se um aumento de desempenho de 5% for alcançado e o código for mais direto, dá uma boa sensação!

O código está aqui:

non_array_0=Math.sqrt(10435.4557);
non_array_1=Math.atan2(12345,24869);
non_array_2=Math.sin(35.345262356547);
non_array_3=Math.cos(232.43575432);
non_array_4=Math.tan(325);
non_array_5=Math.asin(3459.35498534536);
non_array_6=Math.acos(3452.35);
non_array_7=Math.atan(34.346);
non_array_8=Math.pow(234,222);
non_array_9=9374.34524/342734.255;

8. pre_filled_array.push (i) (0.8%):

Empurrar é mal! Empurre combinado para loop é maligno mal! Este é por algum motivo muito lento método para atribuir valores em matriz. O teste 5 (designações diretas em loop) é quase 9 vezes mais rápido que este método e ambos os métodos fazem exatamente a mesma coisa: atribuir 0-9 inteiro em array pré-inicializado e pré-preenchido. Eu não testei se esta maldade push-for-loop é devido a push ou looping ou a combinação de ambos ou a contagem de looping. Existem no JSPERF.COM outros exemplos que fornecem resultados conflitantes. É mais sensato testar apenas com os dados reais e tomar decisões. Esse teste pode não ser compatível com outros dados além do que foi usado.

E aqui está o código:

for(var i=0;i<10;i++)
{
  pre_filled_array.push(i);
}

9. non_pre_filled_array.push (i) (0.74%):

O último e mais lento método neste teste é o mesmo do teste 8, mas o array não é pré-preenchido. Um pouco mais lento que 9, mas a diferença não é significativa (7,23%). Mas vamos dar um exemplo e comparar este método mais lento com o mais rápido.A velocidade deste método é de 0,74% da velocidade do método 1, o que significa que o método 1 é 135 vezes mais rápido do que isso. Portanto, pense com cuidado, se as matrizes forem necessárias em um caso de uso específico. Se for apenas um ou poucos pushes, a diferença de velocidade total não é perceptível, mas, por outro lado, se houver apenas alguns pushes, eles são muito simples e elegantes para converter em variáveis ​​não matriciais.

Este é o código:

for(var i=0;i<10;i++)
{
  non_pre_filled_array.push(i);
}

E finalmente a pergunta SO obrigatória:

Como a diferença de velocidade de acordo com esse teste parece ser tão grande entre atribuições de variáveis ​​não matriciais e atribuições de matrizes, existe algum método para obter a velocidade de atribuições de variáveis ​​não matriciais e a dinâmica de matrizes?

Não posso usarvar variable_$i = 1 em um loop para que $ i seja convertido em algum inteiro. Eu tenho que usarvar variable[i] = 1 que é significativamente mais lento do quevar variable1 = 1 como o teste provou. Isso pode ser crítico somente quando há grandes matrizes e, em muitos casos, são.

EDIT: Eu fiz um novo teste para confirmar a lentidão do acesso de matrizes e tentei encontrar o caminho mais rápido:

http://jsperf.com/read-write-array-vs-variable

Array-read e / ou array-write são significativamente mais lentos do que usando variáveis ​​normais. Se algumas operações são feitas para membros da matriz, é mais sábio armazenar o valor do membro da matriz em uma variável temporária, fazer essas operações na variável temp e, finalmente, armazenar o valor no membro da matriz. E embora o código se torne maior, é significativamente mais rápido fazer essas operações inline do que no loop.

Conclusão: arrays vs variáveis ​​normais são análogas a disk vs memory. Normalmente, o acesso à memória é mais rápido que o acesso ao disco e o acesso às variáveis ​​normais é mais rápido do que o acesso à matriz. E pode ser operações de concatenação também é mais rápido do que usar variáveis ​​intermediárias, mas isso torna o código um pouco não legível.

questionAnswers(1)

yourAnswerToTheQuestion