Script de bash; otimização da velocidade de processamento

9

Eu queria saber se há diretrizes gerais para otimizar os scripts Bash.

  • Por exemplo, é mais conveniente escrever loops do que linhas de comandos, mas também é mais rápido processar para o sistema? Exemplo:

    for i in a b c; do echo $i; done
    
    echo a
    echo b
    echo c
    
  • Às vezes, as pessoas apresentam soluções diferentes para o mesmo problema. Por exemplo, sed, cut, awk e echo são todos capazes de remover dígitos de uma string. Eu queria saber se você pode dizer que quanto menos código de dígitos tiver, mais rápido será se você usar:

    1. o mesmo comando, por exemplo

      STRING=abc.def
      echo ${STRING} | sed 's/.def//g'
      echo ${STRING} | sed '$s/....$//'
      
    2. comandos diferentes, por exemplo,

      STRING=abc.def
      echo ${STRING} | cut -d . -f 1
      echo ${STRING} | sed 's/.def//g'
      
por Vincent 06.03.2013 / 16:49

3 respostas

8

Os shells não fazem qualquer reorganização do código que recebem, ele é interpretado apenas uma linha após a outra (nada mais faz sentido em um interpretador de comandos). A maior parte do tempo gasto pelo shell vai para a análise lexical / parsing / launching dos programas chamados.

Para operações simples (como as que entopem strings nos exemplos no final da pergunta) eu ficaria surpreso se o tempo para carregar os programas não inundar quaisquer diferenças minúsculas de velocidade.

A moral da história é que, se você realmente precisa de mais velocidade, é melhor ter uma linguagem (semi) compilada como Perl ou Python, que é mais rápida de executar para começar, na qual você pode escrever muitos dos operações mencionadas diretamente e não precisam chamar programas externos, e tem a opção de invocar programas externos ou chamar módulos C (ou qualquer outro) otimizados para fazer a maior parte do trabalho. Essa é a razão pela qual no Fedora o "sistema de administração de açúcar" (GUIs, essencialmente) é escrito em Python: pode adicionar uma interface gráfica agradável com pouco esforço, rápido o suficiente para tais aplicações, ter acesso direto às chamadas do sistema. Se isso não for velocidade suficiente, pegue C ++ ou C.

Mas não vá até lá, a menos que você possa provar que o ganho de desempenho vale a perda de flexibilidade e o tempo de desenvolvimento. Scripts shell não são ruins para ler, mas eu estremeço quando lembro de alguns scripts usados para instalar o Ultrix que eu tentei decifrar. Eu desisti, muita "otimização de shell script" foi aplicada.

    
por 06.03.2013 / 17:05
18

A primeira regra de otimização é: não otimize . Teste primeiro. Se os testes mostrarem que seu programa está muito lento, procure possíveis otimizações.

A única maneira de ter certeza é compará-lo ao seu caso de uso. Existem algumas regras gerais, mas elas só se aplicam a volumes típicos de dados em aplicativos típicos.

Algumas regras gerais que podem ou não ser verdadeiras em qualquer circunstância específica:

  • Para processamento interno no shell, o ATT ksh é o mais rápido. Se você faz muitas manipulações de strings, use ATT ksh. Dash vem em segundo lugar; bash, pdksh e zsh lag atrás.
  • Se você precisar invocar um shell com frequência para executar uma tarefa muito pequena a cada vez, o painel ganha por causa do baixo tempo de inicialização.
  • Iniciar um processo externo custa tempo, por isso é mais rápido ter um pipeline com peças complexas do que um pipeline em um loop.
  • echo $foo é mais lento que echo "$foo" , porque sem aspas duplas, divide $foo em palavras e interpreta cada palavra como um padrão de coringa de nome de arquivo. Mais importante, esse comportamento de divisão e globulação raramente é desejado. Portanto, lembre-se de sempre colocar aspas duplas em torno de substituições de variáveis e substituições de comandos: "$foo" , "$(foo)" .
  • Ferramentas dedicadas tendem a conquistar ferramentas de uso geral. Por exemplo, ferramentas como cut ou head podem ser emuladas com sed , mas sed será mais lento e awk será ainda mais lento. O processamento de strings da shell é lento, mas, para strings curtas, ele é muito melhor que chamar um programa externo.
  • Linguagens mais avançadas, como Perl, Python e Ruby, geralmente permitem que você escreva algoritmos mais rápidos, mas eles têm um tempo de inicialização significativamente maior, de modo que valem a pena apenas pelo desempenho de grandes quantidades de dados.
  • No Linux, pelo menos, os canais tendem a ser mais rápidos que os arquivos temporários.
  • A maioria dos usos de script de shell é feita em torno de processos vinculados a E / S, portanto, o consumo de CPU não importa.

É raro que o desempenho seja uma preocupação em scripts de shell. A lista acima é meramente indicativa; Não há problema em usar métodos “lentos” na maioria dos casos, pois a diferença costuma ser uma fração de um percentual.

Normalmente, o objetivo de um script de shell é fazer com que algo seja feito rapidamente. Você precisa ganhar muito com a otimização para justificar gastar minutos extras escrevendo o roteiro.

    
por 07.03.2013 / 02:56
2

We'll expand here on our globbing example above to illustrate some performance characteristics of the shell script interpreter. Comparing the bash and dash interpreters for this example where a process is spawned for each of 30,000 files, shows that dash can fork the wc processes nearly twice as fast as bash

bash-4.2$ time dash -c 'for i in *; do wc -l "$i"; done>/dev/null'
real    0m1.238s
user    0m0.309s
sys     0m0.815s


bash-4.2$ time bash -c 'for i in *; do wc -l "$i"; done>/dev/null'
real    0m1.422s
user    0m0.349s
sys     0m0.940s

Comparing the base looping speed by not invoking the wc processes, shows that dash's looping is nearly 6 times faster!

$ time bash -c 'for i in *; do echo "$i">/dev/null; done'
real    0m1.715s
user    0m1.459s
sys     0m0.252s



$ time dash -c 'for i in *; do echo "$i">/dev/null; done'
real    0m0.375s
user    0m0.169s
sys     0m0.203s

The looping is still relatively slow in either shell as demonstrated previously, so for scalability we should try and use more functional techniques so iteration is performed in compiled processes.

$ time find -type f -print0 | wc -l --files0-from=- | tail -n1
    30000 total
real    0m0.299s
user    0m0.072s
sys     0m0.221s

The above is by far the most efficient solution and illustrates the point well that one should do as little as possible in shell script and aim just to use it to connect the existing logic available in the rich set of utilities available on a UNIX system.

Roubado de Erros comuns da escrita por Pádraig Brady.

    
por 07.03.2013 / 03:19