Estoy tratando de hacer un recuento de registros en un archivo gzip de 7,6 GB. Encontré algunos enfoques usando el zcat
comando.
$ zcat T.csv.gz | wc -l
423668947
Esto funciona, pero lleva demasiado tiempo (más de 10 minutos para obtener el recuento). Intenté algunos enfoques más como
$ sed -n '$=' T.csv.gz
28173811
$ perl -lne 'END { print $. }' < T.csv.gz
28173811
$ awk 'END {print NR}' T.csv.gz
28173811
Estos tres comandos se ejecutan bastante rápido pero dan un recuento incorrecto de 28173811.
¿Cómo puedo realizar un recuento de registros en un tiempo mínimo?
Respuestas:
El
sed
,perl
y losawk
comandos que se pueden mencionar correcta, pero todos ellos leer los comprimidos de datos y los recuentos de caracteres de nueva línea en eso. Estos caracteres de nueva línea no tienen nada que ver con los caracteres de nueva línea en los datos sin comprimir.Para contar el número de líneas en los datos sin comprimir, no hay forma de descomprimirlos. Tu enfoque con
zcat
es el enfoque correcto y dado que los datos es tan grande, que va a tomar tiempo para descomprimirlo.La mayoría de las utilidades que se ocupan de la
gzip
compresión y la descompresión probablemente usarán las mismas rutinas de biblioteca compartida para hacerlo. La única forma de acelerarlo sería encontrar una implementación de laszlib
rutinas que de alguna manera sean más rápidas que las predeterminadas, y reconstruir, por ejemplo,zcat
para usarlas.fuente
zcat
. Una parte importante del trabajo dezcat
generar el resultado real. Pero si solo estás contando\n
personajes, eso no es necesario.gzip
la compresión funciona esencialmente reemplazando cadenas largas comunes por cadenas más cortas. Por lo tanto, solo debe preocuparse por las cadenas largas en el diccionario que contienen a\n
, y contar la aparición (ponderada) de esas. Por ejemplo, debido a las reglas inglesas,.\n
es una cadena común de 16 bits.Use unpigz.
La respuesta de Kusalananda es correcta, deberá descomprimir todo el archivo para escanear su contenido.
/bin/gunzip
hace esto tan rápido como puede, en un solo núcleo. Pigz es una implementación paralelagzip
que puede usar múltiples núcleos.Lamentablemente, la descompresión de archivos en sí gzip normales no se puede paralelizar, pero
pigz
sí ofrece una versión mejoradagunzip
,unpigz
que hace el trabajo relacionado, como la lectura, la escritura, y la suma de control en un hilo separado. En algunos puntos de referencia rápidos,unpigz
es casi el doble de rápido quegunzip
en mi máquina Core i5.Instale
pigz
con su administrador de paquetes favorito y use enunpigz
lugar degunzip
, o enunpigz -c
lugar dezcat
. Entonces su comando se convierte en:Todo esto supone que el cuello de botella es la CPU, no el disco, por supuesto.
fuente
pigz
página de manual dice que la descompresión no se puede paralelizar, al menos no sin flujos de desinflado especialmente preparados para ese propósito. Como resultado, pigz usa un solo subproceso (el subproceso principal) para la descompresión, pero creará otros tres subprocesos para leer, escribir y verificar el cálculo, lo que puede acelerar la descompresión en algunas circunstancias . Aún así, como usted, encuentro que es al menos dos veces más rápido quegzip
, si no es por el paralelismoEl problema con todas las tuberías es que esencialmente está duplicando el trabajo. No importa qué tan rápida sea la descompresión, los datos aún deben transferirse a otro proceso.
Perl tiene PerlIO :: gzip que le permite leer secuencias comprimidas directamente. Por lo tanto, podría ofrecer una ventaja incluso si su velocidad de descompresión puede no coincidir con la de
unpigz
:Lo probé con un archivo comprimido gzip de 13 MB (se descomprime a 1,4 GB) en un viejo MacBook Pro 2010 con 16 GB de RAM y un viejo ThinkPad T400 con 8 GB de RAM con el archivo ya en el caché. En la Mac, el script de Perl fue significativamente más rápido que el uso de tuberías (5 segundos frente a 22 segundos), pero en ArchLinux, perdió debido a la desconexión:
versus
y
Claramente, el uso
unpigz -c file.gz | wc -l
es el ganador aquí tanto en términos de velocidad. Y, esa simple línea de comando seguramente es mejor que escribir un programa, por breve que sea.fuente
gzip | wc
tiene la misma velocidad que su script perl. Ypigz | wc
es el doble de rápido.gzip
se ejecuta con la misma velocidad, independientemente de si escribo la salida en / dev / null o pipe enwc
Lo que creo es que la "biblioteca gzip" utilizada por perl es más rápida que la herramienta de línea de comandos gzip. Quizás haya otro problema específico de Mac / Darwin con las tuberías. Todavía es sorprendente que esta versión perl sea competitiva en absoluto.zcat
y peor queunpigz
. Estoy sorprendido de lo rápido que es la canalización en el sistema Linux en comparación con la Mac. No esperaba eso, aunque debería haberlo hecho, ya que una vez observé que el mismo programa se ejecutó más rápido en una máquina virtual Linux con CPU limitada en esa misma Mac que en el bare metal.zcat | wc -l
y 5.5 segundos para su script perl. Honestamente, estoy sorprendido por la variación que la gente informa aquí, ¡especialmente entre Linux y MacOS X!wc -l
toma 2.5 segundos.gzcat compressed.gz > /dev/null
toma 2.7 segundos Sin embargo, la tubería tarda 22 segundos. Si intento GNUwc
, solo toma medio segundo en el archivo descomprimido, pero 22 segundos en la tubería. GNUzcat
tarda el doble de tiempo en ejecutarsezcat compressed.gz > /dev/null
. Esto está en Mavericks, antigua CPU Core 2 Duo, 16 GB de RAM, SSD Crucial MX100.La respuesta de Kusalananda es mayormente correcta. Para contar líneas necesita buscar nuevas líneas. Sin embargo, es teóricamente posible buscar nuevas líneas sin descomprimir completamente el archivo.
gzip usa la compresión DEFLATE. DEFLATE es una combinación de codificación LZ77 y Huffman. Puede haber una manera de descubrir solo el nodo del símbolo de Huffman para la nueva línea e ignorar el resto. Es casi seguro que hay una forma de buscar nuevas líneas codificadas con L277, mantener un recuento de bytes e ignorar todo lo demás.
Entonces, en mi humilde opinión, es teóricamente posible encontrar una solución más eficiente que unpigz o zgrep. Dicho esto, ciertamente no es práctico (a menos que alguien ya lo haya hecho).
fuente
Se puede hacer usando
zgrep
con-c
bandera y$
parámetro.En este caso, -c indica al comando que muestre el número de líneas coincidentes y la expresión regular $ coincide con el final de línea para que coincida con cada línea o el archivo.
Como se ha comentado por @ StéphaneChazelas -
zgrep
es solamente un guión alrededorzcat
ygrep
y debe proporcionar un rendimiento similar a la sugerencia original dezcat | wc -l
fuente
zgrep
generalmente es un script que invocazcat
(igual quegzip -dcq
) para descomprimir los datos y alimentarlosgrep
, por lo que no va a ayudar.Como puede ver, la mayoría de las respuestas intentan optimizar lo que puede: el número de cambios de contexto y la E / S entre procesos. La razón es que esto es lo único que puede optimizar aquí fácilmente.
Ahora el problema es que su necesidad de recursos es casi insignificante para la necesidad de recursos de la descompresión. Es por eso que las optimizaciones realmente no harán nada más rápido.
Donde realmente podría acelerarse, sería un algoritmo modificado de descompresión (es decir, descompresión), que excluye la producción real del flujo de datos descomprimido; más bien solo calcula el número de las nuevas líneas en el flujo descomprimido del comprimido . Sería difícil, requeriría un conocimiento profundo del algoritmo de gzip (alguna combinación de los algoritmos de compresión LZW y Huffman ). Es bastante probable que el algoritmo no permita optimizar significativamente el tiempo de descompresión con el rayo, que solo necesitamos saber los recuentos de nueva línea. Incluso si fuera posible, esencialmente se debería haber desarrollado una nueva biblioteca de descompresión gzip (no existe hasta que se sepa).
La respuesta realista a su pregunta es que no, no puede hacerlo significativamente más rápido.
Tal vez podría usar alguna descompresión paralela de gzip, si existe. Podría usar múltiples núcleos de CPU para la descompresión. Si no existe, podría desarrollarse con relativa facilidad.
Para el xz , existe un compresor paralelo (pxz).
fuente