Tubos de Python: lo que sucede cuando se lee la salida de forma incremental
Pregunta
Según una sección en este libro presumiblemente exacto ,
Un uso común de las tuberías es leer un archivo comprimido incrementalmente; ese Es, sin descomprimir el conjunto. cosa a la vez. La siguiente funcion Toma el nombre de un archivo comprimido como un parámetro y devuelve un tubo que usa gunzip para descomprimir el contenidos:
def open_gunzip(filename): cmd = 'gunzip -c ' + filename fp = os.popen(cmd) return fp
Si lees líneas de fp uno en un tiempo, nunca tienes que almacenar el archivo sin comprimir en la memoria o en disco.
Tal vez solo estoy interpretando esto mal, pero no veo cómo esto es posible. Python no podía tener ningún medio para detener Gunzip a mitad de camino a través de escupir los resultados, ¿verdad? Supongo que gunzip no se bloqueará hasta que se lea una línea de salida antes de continuar con más líneas, por lo que algún búfer tiene que capturar todo esto (ya sea dentro del intérprete de Python o en el sistema operativo, ya sea en la memoria o en el disco ), lo que significa que el archivo sin comprimir se está almacenando en algún lugar en su totalidad ... ¿verdad?
Solución
Su suposición es defectuosa. Gunzip no tiene que ver el archivo completo para descomprimirlo. Lea el formato de archivo descomprimir. Hay un directorio, con compensaciones para los componentes individuales.
Es posible descomprimir un archivo en pedazos.
" el archivo sin comprimir se está almacenando en algún lugar en su totalidad ... ¿verdad? "
No necesariamente. No estoy seguro de por qué lo estás asumiendo o dónde lo lees.
Se pueden bloquear todas las llamadas de E / S de bajo nivel. La escritura en gunzip, cuando se escribe en una tubería, puede bloquearse cuando la tubería está llena. Así se define la E / S a una tubería. Bloques de E / S de tuberías.
Revise las páginas de manual para obtener más información.
Si un proceso intenta leer desde un tubo vacío, luego leer (2) lo hará
Bloquear hasta que los datos estén disponibles. Si un proceso intenta escribir a un usuario tubo completo (ver más abajo), luego escriba (2) Bloques hasta que suficientes datos tengan
sido leído desde la tubería para permitir que el escribir para completar No bloqueo
I / O es posible usando el fcntl (2) Operación F_SETFL para habilitar el
O_NONBLOCK abre el indicador de estado del archivo.
Otros consejos
Esto realmente viene de la implementación de gunzip
, no de python.
Está escrito en C. Probablemente usa fwrite ()
del stdio.h
de C para escribir su salida.
libc6
que uso automáticamente crea un búfer de salida, y cuando se llena, se bloquea en fwrite ()
hasta que pueda escribir más.
No es Python lo que suspende gunzip
, es que el kernel dejará de ejecutar gunzip
cuando intente escribir (utilizando write ()
syscall) a un búfer completo. Esto se denomina bloqueo en IO . El kernel mantiene un búfer interno que conecta los dos extremos de la línea de tubería, independientemente de cualquier búfer que ocurra en cualquier proceso que esté escribiendo o leyendo desde la tubería.
Python se bloqueará de manera similar cuando lea desde una tubería que tiene un búfer vacío, es decir, que actualmente no tiene ningún dato de gunzip
escrito en él.
Los tubos se pueden ver como una solución para el Problema del productor-consumidor .