¿Utilidad para almacenar una cantidad ilimitada de datos en una tubería?

13

¿Hay alguna utilidad que pueda incluir en una tubería para desacoplar las velocidades de lectura y escritura?

$ producer | buf | consumer

Básicamente, quiero una utilidad bufque lea su entrada lo más rápido posible, almacenándola en la memoria para que consumerpueda tomar su tiempo dulce mientras se producerejecuta lo más rápido posible.

Doctor j
fuente
Me gustaría ver eso también
Antti Haapala
La stdbufherramienta parece ser un sizeparámetro. Sin embargo, no estoy seguro de si funciona.
CMCDragonkai

Respuestas:

13

La pvutilidad (visor de tuberías) puede hacer esto (con la -Bopción) y mucho más, incluso darle informes de progreso.

David Schwartz
fuente
¿Hay alguna manera de hacer esto con una cantidad ilimitada de datos? Lo mejor que puedo decir es que necesito proporcionar un número con -B y si el productor se adelanta mucho al consumidor, el productor disminuirá la velocidad nuevamente. Si se encuentra en una situación en la que hay múltiples consumidores ( producer | tee >(pv -cB $SIZE | consumer1) | pv -cB $SIZE2 | consumer2), esto puede causar ralentizaciones nuevamente.
Daniel H
Lo he usado pvcientos de veces y nunca supe esto. Muy impresionante, gracias!
Rucent88
pv -B 4096 -c -N in /dev/zero | pv -q -B 1000000000 | pv -B 4096 -c -N out -L 100k > /dev/null- Espero que ambos pvextremos sean suaves (aunque uno está 1 GB por delante). No funciona de esta manera, a diferencia dembuffer
Vi.
9

puedes usar dd:

producer | dd obs=64K | consumer

Está disponible en todos los Unix.

Michał Šrajer
fuente
+1 para usar la utilidad estándar, aunque pvprobablemente sea más agradable de usar (muestra el progreso).
Totor
2
¿Eso realmente desacopla la velocidad de lectura y escritura? Parece que ddsolo almacena un bloque a la vez, por lo que solo retrasaría todo por la cantidad de tiempo que lleva producir el tamaño del bloque; Por favor corrígeme si estoy equivocado. Además, ¿se puede extender este almacenamiento en búfer a un tamaño ilimitado, o solo lo que se haya ingresado para el tamaño de bloque?
Daniel H
@DanielH: lo hace ahora.
mikeserv
7

Echa un vistazo a mbuffer . Puede almacenarse en la memoria o en el archivo de memoria asignado ( -t/ -T).

Stephen Paul Lesniewski
fuente
Como pregunté por los otros, ¿hay alguna manera de decirle que se amortigüe tanto como sea necesario, o tiene un tamaño máximo? ¿Existe una razón conceptual por la cual la mayoría de estos programas tienen tamaños máximos y, por ejemplo, no usan una lista vinculada de buffers más pequeños (o cualquier otra implementación de cola de tamaño arbitrario)?
Daniel H
Probablemente para evitar errores de falta de memoria. Probablemente pueda usar una opción para establecer un búfer muy grande (4 GB más o menos) si lo desea (pruébelo).
David Balažic
1

Esto es básicamente una respuesta negativa. Parece que ni dd, ni mbuffer, ni siquiera pvfunciona son todos los casos, en particular si la tasa de datos generados por el productor puede variar mucho. Doy algunos casos de prueba a continuación. Después de escribir el comando, espere unos 10 segundos, luego escriba >(para ir al final de los datos, es decir, espere al final de la entrada).

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

Aquí, después de escribir >, hay que esperar 5 segundos, lo que significa que el productor (secuencia de comandos zsh) ha bloqueado antes que sleep 5. Aumentar el bstamaño a, por ejemplo, 32M no cambia el comportamiento, aunque el búfer de 32MB es lo suficientemente grande. Sospecho que esto se debe a que los ddbloques en la salida en lugar de continuar con la entrada. Usar oflag=nonblockno es una solución porque esto descarta datos.

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

Con mbuffer, el problema es que la primera línea (foo0) no aparece inmediatamente. No parece haber ninguna opción para habilitar el almacenamiento en línea en la entrada.

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

Con pv, el comportamiento es similar a dd. Peor aún, sospecho que hace cosas incorrectas al terminal, ya que a veces lessya no puede recibir información del terminal; por ejemplo, no se puede abandonar con q.

vinc17
fuente
0

Movimiento no estándar: uso de amortiguadores de enchufe.

Ejemplo:

# 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] [       <=>                   ]

Implementado dos herramientas adicionales para esto: buffered_pipeline y 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.
fuente