¿El gato utiliza la evaluación perezosa?

¿El gato utiliza la evaluación perezosa?

Cuando se utilizan tuberías, por ejemplo.

sudo cat /dev/sda | strings | less

Puedo moverme por las líneas de cadenas de mi dispositivo sda. Pero, ¿el contenido del dispositivo sda está completamente cargado y enviado al flujo de salida de cat? ¿O se evalúan las nuevas líneas cada vez que un programa solicita resultados de cat? (es decir, presiono j en el buscapersonas menos)

Respuesta1

Esto tiene más que ver con cómo lessfunciona que con cómo catfunciona strings.

El catcomando solo enviará datos a su salida estándar y se bloqueará siempre que el búfer de canalización entre él y stringsesté lleno y nadie esté leyendo. catrealiza un almacenamiento en búfer mínimo por sí solo y el búfer de tubería suele ser pequeño.

Esto también es válido para strings. Procesará los datos caty se bloqueará cuando lessno esté leyendo los datos que stringsproduce.

lessalmacenará en búfer su entrada para permitirle moverse hacia adelante y hacia atrás en los datos que muestra. Cuando se desplace a la página siguiente, lessleerá más datos stringsen su búfer. Mientras no se esté desplazando hacia adelante, creo que lesssolo leerá una cantidad limitada de datos (y, por lo tanto, stringsse catbloqueará mientras no se esté desplazando hacia adelante).

Si canaliza una gran cantidad de datos a less, se utilizará bastante memoria para este almacenamiento en búfer.sidecides leerlo todo hasta el final con less.

Hay una opción, -Bque limita la cantidad de memoria utilizada para el almacenamiento en búfer a 64 kilobytes (o la cantidad que especifique con la -bopción). Limitar el tamaño del búfer de esta manera evitará que retroceda más de lo que se puede almacenar en el espacio del búfer especificado, pero también le permitirá leer grandes cantidades de datos sin lessquedarse sin memoria.

Consulte también man lessen su sistema.

Respuesta2

Las canalizaciones tienen un espacio de búfer limitado y, si un lector de canalizaciones (como lessen su ejemplo) no lee más datos de la canalización, el escritor se bloqueará después de llenar el búfer. Esto afectará al stringscomando, que a su vez lo bloqueará catuna vez que su canal esté lleno.

Naturalmente, el catcomando no puede leer todo el contenido del dispositivo sda en la memoria principal, por lo que si se cambian bloques que aún no han sido leídos, catverá el contenido modificado.

Respuesta3

Tanto caty stringscomo la mayoría de utilidades similares¹, leen un poco de entrada a la vez, la procesan, luego leen más entradas, y así sucesivamente. Entonces, en su caso, catsolo lee lo que lessse muestra, más un poco más de lo que está en tránsito.

Más detalladamente, el funcionamiento básico de cates:

  • Reserve unos pocos kilobytes de memoria para utilizarlos como búfer.
  • Si bien hay más entradas disponibles:
    • Lea hasta N bytes de entrada en el búfer. (Esto sobrescribe los datos que se escribieron en un ciclo anterior).
    • Escriba el contenido del búfer en la salida.

La operación de escritura se bloquea hasta que haya un lugar para copiar la salida. Cuando la salida de una tubería, la tubería en sí consume un poco de memoria en el núcleo, lo que se llamaamortiguador de tubería. Una vez que esté lleno, si catintenta escribir en la tubería, el intento de escritura se bloquea hasta que haya espacio. Puede haber espacio en el búfer de la tubería cuando el proceso en el extremo de lectura de la tubería lee algunos datos.

El stringsprograma funciona de la misma manera que cat, excepto que no copia toda la entrada, solo partes seleccionadas.

El lessprograma funciona un poco diferente: guarda todo lo que lee en la memoria. No recicla su búfer, sigue haciéndolo crecer mientras siguen llegando más entradas. Sin embargo, la parte de lectura es similar en que lesssolo lee datos cuando los necesita: solo lee hasta la última línea que muestra. , además de un poco más que lee con anticipación si está disponible.

Entonces, cuando ejecutas sudo cat /dev/sda | strings | less, lo que se ha leído /dev/sdaconsta de:

  • Datos que lessya se han mostrado (o pasado).
  • Hasta unos pocos kB de datos lessleídos pero aún no mostrados.
  • Hasta unos pocos kB en el búfer de tubería entre stringsy less.
  • Hasta unos pocos kB en la memoria de strings.
  • Hasta unos pocos kB en el búfer de tubería entre caty strings.
  • Hasta unos pocos kB en la memoria de cat.

Puede observar cuándo cada programa lee y escribe datos rastreando sus llamadas al sistema:

sudo strace -e read,write -o cat.strace cat /dev/sda | strace -e read,write -o cat.strace strings | strace -e read,write -o less.strace less

y mira los *.stracearchivos. También puede verificar cuánto catse ha leído verificando el desplazamiento del archivo, por ejemplo con lsof -p1234o con head /proc/1234/fdinfo/0dónde 1234está el ID del proceso cat.

¹ Entre las utilidades básicas de procesamiento de texto, la principal excepción es sort, que no puede emitir ningún resultado hasta que haya leído toda la entrada: por lo que sabe, la primera línea de salida bien puede ser la última línea de entrada a la que llega.

Respuesta4

En algunos sistemas (por ejemplo, MS-Dos), la canalización se implementa copiando la salida del primer comando en un archivo y luego ejecutando el segundo comando para leer desde este archivo. Unix no lo hace de esa manera.

En Unix es como una línea de producción. Cada etapa funciona simultáneamente, leyendo entradas y produciendo salidas. Si el proceso A produce más rápido de lo que consume el proceso B, entonces hay una acumulación de existencias entre el proceso A y B. Cuando esto es demasiado (½ KiB a 4 KiB), el proceso A se detiene. Cuando no hay stock para que B procese, B se pone en pausa. Los procesos se pausan y se reanudan para mantener bajos los niveles de existencias.

Al código de estos programas no le importa nada de esto. Simplemente lee la entrada y escribe la salida. Si intenta leer antes de que los datos estén disponibles, o intenta escribir antes de que el siguiente proceso esté listo, el sistema operativo lo pausará hasta que esté listo.

Cuando no hay más para leer (y no hay nada más en camino), el lector obtiene un final de archivo y sale. Esto, a su vez, provoca un fin de archivo en el siguiente proceso.

información relacionada