Por que o sed não sai imediatamente depois de gravar a saída?

5

Eu executei sed em um arquivo grande e usei o utilitário pv para ver a rapidez com que ele é lido entrada e escrita de saída. Embora pv mostrasse que o sed lia a entrada e escrevia a saída em cerca de 5 segundos, o sed não saiu por mais 20 a 30 segundos. Por que isso acontece?

Aqui está a saída que vi:

pv -cN source input.txt | sed "24629045,24629162d" | pv -cN output > output.txt
   source: 2.34GB 0:00:06 [ 388MB/s] [==========================================================================================================>] 100%            
   output: 2.34GB 0:00:05 [ 401MB/s] [              <=>                                                                                                           ]
    
por Brandon Liu 11.04.2015 / 01:46

1 resposta

3

Existem dois motivos. Em primeiro lugar, você não diz para q uit.

Considere:

seq 10 | sed -ne1,5p

Nesse caso, embora apenas p rints a primeira metade das linhas de entrada, ele ainda deve ler o resto delas até EOF. Em vez disso:

seq 10|sed 5q

Ele sairá imediatamente.

Você também está trabalhando com um atraso entre cada processo. Então se pv buffers em 4kb, e sed buffers 4kb, então o último pv é 8kb atrás da entrada o tempo todo. É bem provável que os números sejam maiores que isso.

Você pode tentar a opção -u com GNU / BSD / AST sed , mas é quase certo que não irá ajudar o desempenho em grandes entradas.  Se você chamar um GNU sed com -u , será read() para cada byte de entrada. Não olhei para o que os outros fazem nessa situação, mas não tenho motivos para acreditar que eles fariam algo diferente. Todos os três documentos -u significam unbuffered - e esse é um conceito bastante comumente entendido no que diz respeito aos fluxos.

Outra coisa que você pode fazer é explicitamente a saída do sed do line-buffer com o comando w rite e um ou mais nomes w rite-file [s]. Isso ainda vai atrasar um pouco as coisas, mas provavelmente será melhor que a alternativa.

Você pode fazer isso com qualquer sed como:

sed -n 'w outfile'
O comando sed rite do w é sempre imediato - é uma saída sem buffer. E como (por padrão) sed aplica os comandos uma vez por ciclo de linha, sed pode ser facilmente usado para efetivamente efetuar o i / o de buffer de linha mesmo no meio de um pipeline. Dessa forma, pelo menos, você pode manter o segundo pv praticamente atualizado com sed o tempo todo como:

pv ... | sed -n '24629045,24629162!w /dev/fd/1' | pv ...

... embora isso pressuponha um sistema que forneça os /dev/fd/[num] links (o que quer dizer: praticamente qualquer sistema baseado em linux - exceto Android - e muitos outros além ) . Falha na disponibilidade dos links, para fazer a mesma coisa você pode simplesmente criar explicitamente seu próprio pipe com mkfifo e usá-lo como o último stdin de pv e nomeá-lo como sed ' w rite file.

    
por 20.06.2015 / 13:41

Tags