Utilitário para armazenar em buffer uma quantidade ilimitada de dados em um pipeline?

13

Existe um utilitário que eu possa usar em um pipeline para desacoplar as velocidades de leitura e gravação?

$ producer | buf | consumer

Basicamente, eu quero um utilitário bufque leia sua entrada o mais rápido possível, armazenando-a na memória para que consumerpossa levar um bom tempo enquanto producerexecuta o mais rápido possível.

Doctor J
fonte
Eu também gostaria de ver isso
Antti Haapala
A stdbufferramenta parece ser um sizeparâmetro. Não tenho certeza se funciona.
CMCDragonkai

Respostas:

13

O pvutilitário (visualizador de canal) pode fazer isso (com a -Bopção) e muito mais, inclusive fornecendo relatórios de progresso.

David Schwartz
fonte
Existe uma maneira de fazer isso com uma quantidade ilimitada de dados? O melhor que posso dizer, preciso fornecer um número com -B e, se o produtor chegar tão à frente do consumidor, ele diminuirá a velocidade novamente. Se você estiver em uma situação em que há vários consumidores ( producer | tee >(pv -cB $SIZE | consumer1) | pv -cB $SIZE2 | consumer2), isso pode causar lentidão novamente.
Daniel H
Eu usei pvcentenas de vezes e nunca soube disso. Muito incrível, obrigado!
Regent88
pv -B 4096 -c -N in /dev/zero | pv -q -B 1000000000 | pv -B 4096 -c -N out -L 100k > /dev/null- Espero que os dois pvlados sejam suaves (embora um esteja 1 GB à frente). Não funciona assim, ao contrário dembuffer
Vi.
9

você pode usar dd:

producer | dd obs=64K | consumer

Está disponível em todos os unix.

Michał Šrajer
fonte
+1 para usar o utilitário padrão, embora pvprovavelmente seja provavelmente mais agradável de usar (mostra o progresso).
Totor 17/03/2013
2
Isso realmente desacopla a velocidade de leitura e gravação? Parece que ddapenas armazena um bloco de cada vez; portanto, isso atrasaria tudo pela quantidade de tempo necessária para produzir o tamanho do bloco; Por favor me corrija se eu estiver errado. Além disso, esse buffer pode ser estendido para tamanho ilimitado ou apenas o que for inserido no tamanho do bloco?
Daniel H
@ DanielH - faz agora.
mikeserv
7

Dê uma olhada no mbuffer . Pode armazenar em buffer na memória ou no arquivo mapeado na memória ( -t/ -T).

Stephen Paul Lesniewski
fonte
Como eu pedi para os outros, existe uma maneira de dizer a ele para armazenar em buffer o quanto for necessário ou ele tem um tamanho máximo? Existe uma razão conceitual para a maioria desses programas ter tamanhos máximos e, por exemplo, não usar uma lista vinculada de buffers menores (ou qualquer outra implementação de fila de tamanho arbitrário)?
Daniel H
Provavelmente para evitar erros de falta de memória. Provavelmente, você pode usar uma opção para definir um buffer muito grande (4 GB ou mais), se desejar (experimente).
David Balažic
1

Esta é basicamente uma resposta negativa. Parece que nem dd, nem mbuffer, nem pvfunciona, são todos os casos, principalmente se a taxa de dados gerados pelo produtor puder variar muito. Dou alguns casos de teste abaixo. Após digitar o comando, aguarde cerca de 10 segundos e digite >(para ir para o final dos dados, ou seja, aguarde o final da entrada).

zsh -c 'echo foo0; sleep 3; \
        printf "Line %060d\n" {1..123456}; \
        echo foo1; sleep 5; \
        echo foo2' | dd bs=64K | less

Aqui, depois de digitar >, é necessário aguardar 5 segundos, o que significa que o produtor (script zsh) foi bloqueado antes do sleep 5. Aumentar o bstamanho para, por exemplo, 32M não altera o comportamento, embora o buffer de 32MB seja grande o suficiente. Eu suspeito que isso ocorre porque ddbloqueia a saída em vez de continuar com a entrada. Usandooflag=nonblock não é uma solução porque isso descarta dados.

zsh -c 'echo foo0; sleep 3; \
        printf "Line %060d\n" {1..123456}; \
        echo foo1; sleep 5; \
        echo foo2' | mbuffer -q | less

Com mbuffer, o problema é que a primeira linha (foo0) não aparece imediatamente. Não parece haver nenhuma opção para ativar o buffer de linha na entrada.

zsh -c 'echo foo0; sleep 3; \
        printf "Line %060d\n" {1..123456}; \
        echo foo1; sleep 5; \
        echo foo2' | pv -q -B 32m | less

Com pv, o comportamento é semelhante a dd. Pior, suspeito que ele faça coisas erradas no terminal, pois às vezes lessnão pode mais receber informações do terminal; por exemplo, não se pode desistir q.

vinc17
fonte
0

Movimento fora do padrão: usando buffers de soquete.

Exemplo:

# echo 2000000000 > /proc/sys/net/core/wmem_max
$ socat -u system:'pv -c -N i /dev/zero',sndbuf=1000000000 - | pv -L 100k -c -N o > /dev/null
        i:  468MB 0:00:16 [ 129kB/s] [  <=>                        ]
        o: 1.56MB 0:00:16 [ 101kB/s] [       <=>                   ]

Implementou duas ferramentas adicionais para isso: buffered_pipeline e mapopentounixsocket

$ ./buffered_pipeline ! pv -i 10 -c -N 1 /dev/zero ! $((20*1000*1000)) ! pv -i 10 -L 100k -c -N 2 ! > /dev/zero
        1: 13.4MB 0:00:40 [ 103kB/s] [         <=>      ]
        2: 3.91MB 0:00:40 [ 100kB/s] [         <=>      ]
Vi.
fonte