AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 506892
Accepted
Weijun Zhou
Weijun Zhou
Asked: 2019-03-18 14:49:28 +0800 CST2019-03-18 14:49:28 +0800 CST 2019-03-18 14:49:28 +0800 CST

Por que o `sed` no op é muito mais rápido que o `awk` neste caso

  • 772

Estou tentando entender alguns problemas de desempenho relacionados a sede awk, e fiz o seguinte experimento,

$ seq 100000 > test
$ yes 'NR==100001{print}' | head -n 5000 > test.awk
$ yes '100001{p;b}' | head -n 5000 > test.sed
$ time sed -nf test.sed test
real    0m3.436s
user    0m3.428s
sys     0m0.004s
$ time awk -F@ -f test.awk test
real    0m11.615s
user    0m11.582s
sys     0m0.007s
$ sed --version
sed (GNU sed) 4.5
$ awk --version
GNU Awk 4.2.1, API: 2.0 (GNU MPFR 3.1.6-p2, GNU MP 6.1.2)

Aqui, como o arquivo de teste contém apenas 100.000 linhas, todos os comandos test.sede test.awksão no-ops. Ambos os programas só precisam combinar o número da linha com o endereço (in sed) ou NR(in awk) para decidir que o comando não precisa ser executado, mas ainda há uma grande diferença no custo de tempo. Por que é o caso? Existe alguém com versões diferentes sede awkinstaladas que dê um resultado diferente neste teste?

Edit : Os resultados para mawk(como sugerido por @mosvy), original-awk(o nome para "one true awk" em sistemas baseados em debian, sugeridos por @GregA.Woods) e perlsão fornecidos abaixo,

$ time mawk -F@ -f test.awk test
real    0m5.934s
user    0m5.919s
sys     0m0.004s
$ time original-awk -F@ -f test.awk test
real    0m8.132s
user    0m8.128s
sys     0m0.004s
$ yes 'print if $.==100001;' | head -n 5000 > test.pl
$ time perl -n test.pl test
real    0m33.245s
user    0m33.110s
sys     0m0.019s
$ mawk -W version
mawk 1.3.4 20171017
$ perl --version
This is perl 5, version 28, subversion 1 (v5.28.1) built for x86_64-linux-thread-multi

A substituição -F@por -F ''não faz alterações observáveis ​​no caso de gawke mawk. original-awknão suporta vazio FS.

Edit 2 O teste de @mosvy dá resultados diferentes, 21s para sede 11s para mawk, veja o comentário abaixo para mais detalhes.

awk sed
  • 2 2 respostas
  • 1118 Views

2 respostas

  • Voted
  1. Best Answer
    JigglyNaga
    2019-03-20T09:08:30+08:002019-03-20T09:08:30+08:00

    awktem um conjunto de recursos mais amplo do que sed, com uma sintaxe mais flexível. Portanto, não é irracional que demore mais para analisar seus scripts e executá-los.

    Como seu comando de exemplo (a parte dentro das chaves) nunca é executado, a parte sensível ao tempo deve ser sua expressão de teste.

    awk

    Primeiro, veja o teste no awkexemplo:

    NR==100001
    

    e veja os efeitos disso em gprof(GNU awk 4.0.1):

      % auto total cumulativo
     tempo segundos segundos chamadas s/call s/call name
     55,89 19,73 19,73 1 19,73 35,04 interpretar
      8,90 22,87 3,14 500000000 0,00 0,00 cmp_escalar
      8,64 25,92 3,05 1000305023 0,00 0,00 free_wstr
      8,61 28,96 3,04 500105014 0,00 0,00 mk_number
      6,09 31,11 2,15 500000001 0,00 0,00 cmp_nodes
      4,18 32,59 1,48 500200013 0,00 0,00 sem referência
      3,68 33,89 1,30 500000000 0,00 0,00 eval_condition
      2,21 34,67 0,78 500000000 0,00 0,00 atualização_NR
    

    ~50% do tempo é gasto em "interpretar", o loop de nível superior para executar os opcodes resultantes do script analisado.

    Toda vez que o teste é executado (ou seja, 5.000 linhas de script * 100.000 linhas de entrada), awkdeve-se:

    • Busque a variável interna "NR" ( update_NR).
    • Converta a string "100001" ( mk_number).
    • Compare-os ( cmp_nodes, cmp_scalar, eval_condition).
    • Descarte quaisquer objetos temporários necessários para a comparação ( free_wstr, unref)

    Outras awkimplementações não terão exatamente o mesmo fluxo de chamadas, mas ainda terão que recuperar variáveis, converter automaticamente e comparar.

    sed

    Em comparação, em sed, o "teste" é muito mais limitado. Pode ser apenas um único endereço, um intervalo de endereços ou nada (quando o comando é a primeira coisa na linha), e sedpode dizer desde o primeiro caractere se é um endereço ou comando. No exemplo é

    100001
    

    ...um único endereço numérico. O perfil (GNU sed 4.2.2) mostra

      % auto total cumulativo
     tempo segundos segundos chamadas s/call s/call name
     52,01 2,98 2,98 100000 0,00 0,00 execute_programa
     44,16 5,51 2,53 1000000000 0,00 0,00 match_address_p
      3,84 5,73 0,22 match_an_address_p
    [...]
      0,00 5,73 0,00 5000 0,00 0,00 in_inteiro
    

    Novamente, cerca de 50% do tempo está no nível superior execute_program. Nesse caso, é chamado uma vez por linha de entrada e, em seguida, faz um loop sobre os comandos analisados. O loop começa com uma verificação de endereço, mas isso não é tudo o que ele faz no seu exemplo (veja mais adiante).

    Os números de linha no script de entrada foram analisados ​​em tempo de compilação ( in_integer). Isso só precisa ser feito uma vez para cada número de endereço na entrada, ou seja. 5000 vezes e não contribui significativamente para o tempo de execução geral.

    Isso significa que a verificação de endereço, match_address_p, compara apenas inteiros que já estão disponíveis (através de structs e ponteiros).

    sedmelhorias adicionais

    O perfil mostra que match_address_pé chamado 2*5000*100000 vezes, ou seja. duas vezes por linha de script*linha de entrada. Isso ocorre porque, nos bastidores, o GNU sedtrata o comando "start block"

    100001{...}
    

    como uma ramificação negada até o final do bloco

    100001!b end; ... :end
    

    Essa correspondência de endereço é bem- sucedida em todas as linhas de entrada, causando um desvio para o final do bloco ( }). Esse final de bloco não tem endereço associado, portanto, é outra correspondência bem-sucedida. Isso explica por que tanto tempo é gasto em execute_program.

    Portanto, essa sedexpressão seria ainda mais rápida se omitisse o não utilizado ;b, e o resultante desnecessário {...}, deixando apenas o 100001p.

      % auto total cumulativo           
     tempo segundos segundos chamadas s/call s/call name    
     71,43 1,40 1,40 500000000 0,00 0,00 match_address_p
     24,49 1,88 0,48 100000 0,00 0,00 execute_programa
      4,08 1,96 0,08 match_an_address_p
    

    Isso reduz pela metade o número de match_address_pchamadas e também reduz a maior parte do tempo gasto execute_program(porque a correspondência de endereço nunca é bem-sucedida).

    • 8
  2. jf1
    2019-03-20T06:35:33+08:002019-03-20T06:35:33+08:00

    Na verdade, o script acima não é um noop para awk:

    Mesmo que não utilize o conteúdo dos campos, de acordo com o manual do GAWK para cada registro que for lido, os seguintes passos são inevitavelmente executados:

    • varredura para todas as ocorrências do FS
    • divisão de campo
    • atualizando a variável NF

    Se você não estiver usando essas informações, elas serão descartadas posteriormente.

    Se um separador de campo não ocorrer dentro do registro, o awk ainda terá que atribuir o texto a $0 (e no seu caso também a $1) e definir NF para o número real de campos obtidos (1 no exemplo acima)

    • 1

relate perguntas

  • Como posso melhorar este script de conversão de personagens?

  • Como remover uma única linha entre duas linhas

  • Reorganize as letras e compare duas palavras

  • Embaralhamento de arquivo de várias linhas

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve