Author: rapideuphoria.com
Dicas de desempenho da Euphoria
Em qualquer linguagem de programação, e especialmente em Euphoria, você realmente precisa fazer medições antes de tirar conclusões sobre o desempenho. A Euphoria fornece os dois perfil de contagem de execução, assim como perfil de tempo (DOS32 somente). Veja o refman.doc. Muitas vezes, você ficará surpreso com os resultados desses perfis. Concentre seus esforços nos lugares do seu programa que estão usando uma alta porcentagem do tempo total (ou pelo menos são executados um grande número de vezes). Não é necessário reescrever uma seção do código que usa 0,01% do tempo total. Normalmente, haverá um lugar, ou apenas alguns lugares onde o ajuste do código fará uma diferença significativa. Você também pode medir a velocidade do código usando a função time(). por exemplo, atom t t = time() for i = 1 to 10000 do -- small chunk of code here end for ? time() - t Você pode reescrever o pequeno fragmento de código de maneiras diferentes para ver qual é o caminho mais rápido.
Perfilamento irá mostrar-lhe os melhores pontos no seu programa. Estes são geralmente loops internos. Olhe para cada cálculo dentro do loop e pergunte-se se realmente precisa acontecer toda vez através do loop, ou poderia ser feito apenas uma vez, antes do loop.
A adição é mais rápida do que a multiplicação. Às vezes, você pode substituir uma multiplicação pela variável de loop, com uma adição. Algo como: for i = 0 to 199 do poke(screen_memory+i*320, 0) end forse torna: x = screen_memory for i = 0 to 199 do poke(x, 0) x = x + 320 end for Salvando Resultados em Variáveis
Se você tem uma rotina bastante pequena e rápida, mas é chamada de muitas vezes, você economizará tempo fazendo a operação em linha, em vez de chamar a rotina. Seu código pode tornar-se menos legível, portanto, talvez seja melhor in-line apenas em locais que geram muitas chamadas para a rotina.
A Euphoria permite que você opere em uma grande seqüência de dados usando uma única declaração. Isso evita que você escreva um loop onde você processa um elemento ao mesmo tempo. por exemplo. x = {1,3,5,7,9} y = {2,4,6,8,10} z = x + yversos: z = repeat(0, 5) -- if necessary for i = 1 to 5 do z[i] = x[i] + y[i] end for Na maioria dos idiomas interpretados, é muito mais rápido processar toda uma seqüência (matriz) em uma declaração, do que é executar operações escalares em um loop. Isso ocorre porque o intérprete possui uma grande quantidade de despesas gerais para cada declaração que executa. A Euphoria é diferente. A Euphoria é muito magra, com pequena sobrecarga interpretativa, então as operações em seqüências nem sempre ganham. A única solução é o tempo das duas maneiras. O custo por elemento geralmente é menor quando você processa uma seqüência em uma declaração, mas há despesas gerais associadas com a alocação e desalocação de seqüências que podem inclinar a escala do outro lado.
A Euphoria otima automaticamente certos casos especiais. x e y abaixo podem ser variáveis ou expressões arbitrárias. x + 1 -- faster than general x + y 1 + x -- faster than general y + x x * 2 -- faster than general x * y 2 * x -- faster than general y * x x / 2 -- faster than general x / y floor(x/y) -- where x and y are integers, is faster than x/y floor(x/2) -- faster than floor(x/y) x abaixo é uma variável simples, y é qualquer variável ou expressão: x = append(x, y) -- faster than general z = append(x, y) x = prepend(x, y) -- faster than general z = prepend(x, y) x = x & y -- where x is much larger than y, -- is faster than general z = x & yQuando você escreve um loop que "cresce" uma seqüência, anexando ou concatenando dados, o tempo, em geral, crescerá em proporção ao quadrado do número (N) dos elementos que você está adicionando. No entanto, se você pode usar uma das formas otimizadas especiais de anexar (), prepend () ou concatenação listadas acima, o tempo crescerá em proporção apenas a N (grosso modo). Isso poderia poupar um grande quantidade de tempo ao criar uma sequência extremamente longa. (Você também pode usar repeat () para estabelecer o tamanho máximo da seqüência e, em seguida, preencha os elementos em um loop, conforme discutido abaixo.)
Para maior velocidade, converta: left-hand-side = left-hand-side op expressionpara: left-hand-side op= expressionsempre que o lado esquerdo contém pelo menos 2 subíndices, ou pelo menos um subíndice e uma fatia. Em todos os casos mais simples, as duas formas funcionam à mesma velocidade (ou muito próximas da mesma).
Escrevendo texto na tela usando puts() ou printf() é bastante lento. Se necessário, em DOS32, você pode fazê-lo muito mais rápido, puxando para a memória de vídeo, ou usando display_text_image(). Há uma sobrecarga muito grande em cada um puts() para a tela, e um custo incremental relativamente pequeno por personagem. A sobrecarga com exw (WIN32) é especialmente alto (no mínimo no Windows 95/98 / ME). Linux e FreeBSD estão em algum lugar entre DOS32 e WIN32 na velocidade de saída de texto. Portanto, faz sentido construir uma string longa antes de colocar puts (), em vez de chamá-lo para cada personagem. Não há nenhuma vantagem para construir uma string com mais de uma linha no entanto. A lentidão da saída de texto deve-se principalmente à sobrecarga do sistema operacional.
Algumas rotinas comuns são extremamente rápidas. Você provavelmente não poderia fazer o trabalho mais rápido de qualquer outra forma, mesmo se você usasse C ou linguagem de montagem. Alguns destes são:
Outras rotinas são razoavelmente rápidas, mas você pode ser capaz de fazer o trabalho mais rápido em alguns casos se a velocidade fosse crucial. x = repeat(0,100) for i = 1 to 100 do x[i] = i end foré um pouco mais rápido do que: x = {} for i = 1 to 100 do x = append(x, i) end forporque append() tem que alocar e redistribuir o espaço à medida que x cresce em tamanho. Com repeat(), O espaço para x é alocado uma vez no início. (append () é inteligente o suficiente para não alocar espaço com cada append para x. Ele alocará um pouco mais do que ele precisa, para reduzir o número de reafectações.) Você pode substituir: remainder(x, p)com: and_bits(x, p-1)para maior velocidade quando p é uma potência positiva de 2. x deve ser um número inteiro não negativo que se encaixa em 32 bits. arctan() is faster than arccos() or arcsin().
O find() da Euphoria é a maneira mais rápida de procurar um valor em uma seqüência até cerca de 50 elementos. Além disso, você pode considerar uma hash table (demo\hash.ex) ou uma árvore binária (demo\tree.ex).
Na maioria dos casos, você pode usar a rotina do tipo de shell em include\sort.e. Se você tiver uma grande quantidade de dados para classificar, você pode tentar um dos tipos em demo\allsorts.e (por exemplo, great sort). Se seus dados forem muito grandes para caber na memória, não confie na capacidade de troca automática de memória da Euphoria. Em vez disso, classifique alguns milhares de registros por vez e escreva-os para uma série de arquivos temporários. Em seguida, junte todos os arquivos temporários classificados em um grande arquivo ordenado. Se os seus dados consistem apenas em números inteiros, e eles estão todos em um alcance bastante estreito, experimente o tipo de balde em demo\allsorts.e.
À medida que as velocidades da CPU aumentam, a diferença entre a velocidade da memória cache no chip e a velocidade da memória principal ou DRAM (memória dinâmica de acesso aleatório) torna-se cada vez maior. Você pode ter 256 Mb de DRAM no seu computador, mas o cache no chip provavelmente será apenas 8K (dados) mais 8K (instruções) em um Pentium, ou 16K (dados) mais 16K (instruções) em um Pentium com MMX ou um Pentium II / III. A maioria das máquinas também terá um cache de "nível 2" de 256K ou 512K. Um algoritmo que passa por uma seqüência longa de alguns mil elementos ou mais, muitas vezes, do começo ao fim, realizando uma pequena operação em cada elemento, não usará o cache de dados no chip. Pode ser melhor passar uma vez, aplicando várias operações a cada elemento, antes de passar para o próximo elemento. O mesmo argumento é válido quando o seu programa começa a trocar, e os dados mais usados recentemente são movidos para o disco. Esses efeitos de cache não são tão visíveis em Euphoria como eles são em linguagens compiladas de nível inferior, mas são mensuráveis.
A Euphoria permite que você chame as rotinas escritas no código de máquina Intel de 32 bits. Em WIN32 e Linux e FreeBSD você pode chamar rotinas C em .dll ou .então arquivos, e essas rotinas C podem chamar suas rotinas Euphoria. Talvez seja necessário chamar C ou o código da máquina devido a algo que não pode ser feito diretamente na Euphoria, ou você pode fazê-lo para aumentar a velocidade. Para aumentar a velocidade, o código da máquina ou a rotina C precisam fazer uma quantidade significativa de trabalho em cada chamada, caso contrário a sobrecarga de configurar os argumentos e fazer a chamada irá dominar o tempo, e pode não ganhar muito. Muitos programas têm alguma operação de núcleo interno que consome a maior parte do tempo de CPU. Se você pode codificar isso em C ou código de máquina, deixando a maior parte do programa em Euphoria, você pode alcançar uma velocidade comparável a C, sem sacrificar a segurança e a flexibilidade da Euphoria.
Na versão 3.0, o Translator Euphoria To C completo está incluído no pacote de instalação. Ele irá traduzir qualquer programa Euphoria em um conjunto de arquivos de origem C que você pode compilar usando um compilador C. O arquivo executável que você usa usando o Tradutor deve executar o mesmo, mas mais rápido do que quando você usa o intérprete. A aceleração pode ser de alguns por cento para um fator de 5 ou mais.
|