Para un archivo realmente grande como 1GB wc -l
resulta ser lento. ¿Tenemos una forma más rápida de calcular el número de líneas nuevas para un archivo en particular?
command-line
wc
prosti
fuente
fuente
0x0A
, la E / S es sin duda el cuello de botella.wc
tiene demasiada sobrecarga, puede intentar implementar la suyaforeach byte in file: if byte == '\n': linecount++
. Si se implementa en C o ensamblador, no creo que sea más rápido, excepto tal vez en el espacio del kernel en un RTOS con la máxima prioridad (o incluso usar una interrupción para eso; simplemente no puede hacer nada más con el sistema). .. de acuerdo, estoy divagando ;-))time wc -l some_movie.avi
en un archivo sin caché, lo que resultó en5172672 some_movie.avi -- real 0m57.768s -- user 0m0.255s -- sys 0m0.863s
. Lo que básicamente demuestra que @thrig es correcto, la E / S destruye su rendimiento en este caso.time wc -l some_large_file_smaller_than_cache
dos veces seguidas y ver qué tan rápida es la segunda operación,time wc -l some_large_file_larger_than_cache
y ver cómo el tiempo no cambia entre las ejecuciones. Para un archivo de ~ 280MB aquí, el tiempo va de 1.7 segundos a 0.2 segundos, pero para un archivo de 2GB son 14 segundos las dos veces./usr/bin/time wc -l <file>
dice? ¿Cuál es tu hardware? ¿Es más rápido si ejecuta el comando repetidamente? Realmente necesitamos más información;)Respuestas:
Puedes intentar escribir en C:
Guardar en, por ejemplo,
wcl.c
compilar, por ejemplo, congcc wcl.c -O2 -o wcl
y ejecutar conEsto encuentra nuevas líneas esparcidas en un archivo de 1 GB en mi sistema en aproximadamente 370 ms ( ejecuciones repetidas). (Aumentar el tamaño del búfer aumenta ligeramente el tiempo, lo cual es de esperar; BUFSIZ debería estar cerca de lo óptimo). Esto es muy comparable a los ~ 380 ms que estoy obteniendo
wc -l
.Mmaping me da un mejor tiempo de aproximadamente 280 ms , pero por supuesto tiene la limitación de estar limitado a archivos reales (sin FIFOS, sin entrada de terminal, etc.):
Creé mi archivo de prueba con:
y agregó algunas nuevas líneas de prueba con:
y un editor hexadecimal.
fuente
for
bucle OpenMP ) para que se pueda avanzar mientras se detiene un subproceso en espera de entrada. Pero, por otro lado, puede dificultar la programación de E / S, por lo que todo lo que puedo recomendar es probarlo y medir.read()
versión puede beneficiarse de la lectura anticipada.Puede mejorar la solución sugerida por @pskocik reduciendo el número de llamadas a
read
. Hay muchas llamadas para leerBUFSIZ
fragmentos de un archivo de 1 Gb. El enfoque habitual para hacerlo es aumentar el tamaño del búfer:BUFSIZ
es 8192. Con el programa original, eso es 120 mil operaciones de lectura. Probablemente pueda permitirse un búfer de entrada de 1Mb para reducir eso en un factor de 100.Al realizar una evaluación comparativa de los diversos enfoques, debe tener en cuenta que algunos sistemas (como Linux) utilizan la mayor parte de la memoria no utilizada de su máquina como caché de disco. Hace un tiempo (hace casi 20 años, mencionado en las preguntas frecuentes viles ), me sorprendieron los resultados inesperadamente buenos de un algoritmo de paginación (no muy bueno) que había desarrollado para manejar condiciones de poca memoria en un editor de texto. Me explicaron que funcionaba rápido porque el programa funcionaba desde las memorias intermedias utilizadas para leer el archivo, y que solo si el archivo se volvía a leer o escribir, habría una diferencia en la velocidad.
Lo mismo se aplica a
mmap
(en otro caso aún en mi lista de tareas pendientes para incorporar a un FAQ, un desarrollador reportó muy buenos resultados en un escenario donde la memoria caché del disco fue la razón real para mejorar). El desarrollo de puntos de referencia requiere tiempo y cuidado para analizar las razones del buen (o mal) desempeño.Otras lecturas:
fuente
dd
buffers de 1 MB son más lentas que 8 KB. El valor predeterminado de 8 KB para wc en realidad se elige bastante bien, será casi óptimo para una amplia gama de sistemas.