Por qué una tubería se "atasca": buffering
- Descripción del problema: Al ejecutar el comando
tail -f /some/log/file | grep thing1 | grep thing2 para buscar cierta salida en un archivo de logs, si las líneas del log se agregan lentamente, puede ocurrir que no aparezca ninguna salida. Parece que la tubería se quedó atascada, pero en realidad el programa no está escribiendo datos en la tubería.
La causa del buffering
- Por qué existe el buffering: Es normal que los programas hagan buffering antes de escribir datos a una tubería o a un archivo. Esto mejora el rendimiento, porque en vez de escribir cada salida de inmediato, juntan cierta cantidad de datos y los escriben de una sola vez.
- Ejemplo:
grep thing1 guarda los datos coincidentes hasta reunir 8 KB, y por eso puede que la salida no aparezca.
Cuando escriben a la terminal, no hacen buffering
- Diferencia entre terminal y tubería:
grep usa buffering por línea cuando la salida va a la terminal, pero usa buffering por bloques cuando va a una tubería. Esto se determina mediante la función isatty.
Comandos que hacen buffering y comandos que no
- Comandos que no hacen buffering:
tail, cat, tee, etc. no hacen buffering.
- Comandos que sí hacen buffering:
grep, sed, awk, tcpdump, jq, tr, cut, etc. sí hacen buffering, y en algunos casos se puede desactivar con flags específicos.
El buffering de salida predeterminado en lenguajes de programación
- Lenguajes que hacen buffering: C, Python, Ruby, Perl, etc. hacen buffering de salida por defecto, aunque puede desactivarse de ciertas maneras.
Pérdida del contenido del buffer al presionar Ctrl-C
- Descripción del problema: Al presionar
Ctrl-C, se pierde el contenido que está en el buffer. Esto pasa porque primero se entrega la señal SIGINT.
- Solución: Si encuentras el PID de
tcpdump y ejecutas kill -TERM $PID, puedes forzar el vaciado del buffer.
También hay buffering al redirigir a un archivo
- Redirección a archivo: Cuando rediriges a un archivo también hay buffering, pero no ocurre el problema de perder el contenido del buffer por culpa de
Ctrl-C.
Varias formas de evitar el buffering
- Solución 1: Ejecutar un programa que termine rápido.
- Solución 2: Usar el flag
--line-buffered de grep.
- Solución 3: Usar
awk.
- Solución 4: Usar
stdbuf.
- Solución 5: Usar
unbuffer.
Variable de entorno para desactivar el buffering
- Idea: Sería bueno tener una variable de entorno estándar como
PYTHON_UNBUFFERED. Se propone una variable como NO_BUFFER.
Contenido omitido
- Temas omitidos: La diferencia entre buffering por línea y ausencia total de buffering, la diferencia entre el buffering de stderr y stdout, y el buffering del driver TTY del sistema operativo.
1 comentarios
Comentarios de Hacker News
El acceso con búfer debería vaciarse después de cierta cantidad de bytes o de cierto tiempo. Es una forma común de resolver problemas similares en interfaces de hardware
Cuando la CPU de todo el sistema queda inactiva, me gustaría vaciar todos los búferes
Llevo más de 20 años trabajando con sistemas NIX, pero siempre se me olvida el tema del buffering
He usado Unix por más de 35 años, pero nunca había entendido del todo cómo funciona el buffering. Esta explicación fue útil
Se está confundiendo “sin búfer” con “buffer por línea”
Los búferes existen porque escribir en un búfer es relativamente mucho más lento que imprimir salida en pantalla
Al presionar Ctrl-C, el contenido del búfer puede perderse
He tenido problemas de buffering en Unix, y no todas las implementaciones de
awkse comportan igualSiento que no entendí el chiste del pipe congelado