2 puntos por GN⁺ 2024-11-30 | 1 comentarios | Compartir por WhatsApp

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

 
GN⁺ 2024-11-30
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

    • Las bibliotecas que hacen buffering en espacio de usuario deberían configurar un temporizador adecuado cuando empiezan a almacenar datos en el búfer
    • El parámetro de tiempo de espera conviene pasarlo como argumento, o establecerlo un poco por debajo de la escala temporal humana, o en proporción al ancho de banda/umbral, o al overhead del vaciado
    • Aplica tanto a escritura como a lectura, y puede variar según el canal de datos
  • Cuando la CPU de todo el sistema queda inactiva, me gustaría vaciar todos los búferes

    • El buffering normalmente es una técnica para ahorrar CPU
    • Cuando la CPU queda inactiva, debería enviarse una señal a todos los procesos diciendo “vacíen el búfer”
  • 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”

    • Trabajar sin búfer puede degradar el rendimiento y, cuando varias fuentes escriben en el mismo pipe, puede generar una salida incorrecta
    • El buffer por línea es el valor predeterminado en la terminal y es adecuado para pipes
  • Los búferes existen porque escribir en un búfer es relativamente mucho más lento que imprimir salida en pantalla

    • Es un problema que aparece seguido al trabajar con UART, y hay varias soluciones
    • Hay distintos métodos, como usar caracteres especiales, enfoques basados en longitud o basados en tiempo
  • Al presionar Ctrl-C, el contenido del búfer puede perderse

    • La mayoría piensa que los programas vaciarán el búfer al recibir SIGINT
  • He tenido problemas de buffering en Unix, y no todas las implementaciones de awk se comportan igual

  • Siento que no entendí el chiste del pipe congelado