2011-05-10 11 views
7

Tengo un archivo de texto simple que es ~ 150mb. Mi código leerá cada línea, y si coincide con ciertas expresiones regulares, se escribe en un archivo de salida. Pero en este momento, sólo se necesita mucho tiempo para recorrer todas las líneas del archivo (varios minutos) haciendo comoLa forma más rápida de analizar un archivo grande en Ruby

File.open(filename).each do |line| 
    # do some stuff 
end 

Sé que es el bucle a través de las líneas del archivo que se encuentra Tomando un tiempo porque incluso si no hago nada con los datos en "#hacer algunas cosas", todavía lleva mucho tiempo.

Sé que algunos programas Unix pueden analizar archivos grandes como este casi al instante (como grep), entonces me pregunto por qué Ruby (MRI 1.9) tarda tanto en leer el archivo, y hay alguna manera de hacerlo más rápido ?

+0

¿Ha considerado usar 'sed'? –

+0

@Austin Me gustaría hacer esto en ruby ​​puro –

+1

No puedo reproducir esto. Iterar a través de un archivo de 150 MB requiere menos de un segundo aquí. Ciertamente más lento que grep, pero no en la medida en que lo describes. ¿El archivo puede tener líneas muy largas? En ese caso, leer por partes en lugar de líneas podría ayudar (si eso es posible en absoluto con lo que estás tratando de hacer). – sepp2k

Respuesta

3
File.readlines.each do |line| 
    #do stuff with each line 
end 

Leerá el archivo completo en un conjunto de líneas. Debería ser mucho más rápido, pero requiere más memoria.

+2

[Los puntos de referencia muestran que 'readlines' no es tan rápido como usar' foreach' para archivos grandes] (http: // stackoverflow.com/questions/25189262/why-is-slurping-a-file-bad). Tampoco es escalable. Use 'foreach' en lugar de' readlines' y el código seguirá siendo el mismo, solo se escalará y se ejecutará más rápido cuanto más grande sea el archivo que lee. –

4

No es realmente justo compararlo con grep porque es una utilidad muy ajustada que solo escanea los datos, no almacena nada de eso. Cuando estás leyendo ese archivo usando Ruby, terminas asignando memoria para cada línea y luego liberándola durante el ciclo de recolección de basura. grep es una máquina de procesamiento de expresiones regulares bastante pobre y media.

Usted puede encontrar que usted puede alcanzar la velocidad deseada mediante el uso de un programa externo como grep llamada usando system oa través de la instalación de la tubería:

`grep ABC bigfile`.split(/\n/).each do |line| 
    # ... (called on each matching line) ... 
end 
+0

pero lo que específicamente hace que Ruby sea tan lento para leer las líneas de un archivo en comparación con grep. Supongamos que Ruby no procesa absolutamente en esas líneas, solo las lee y sale. –

+3

Ruby tiene que asignar memoria para cada línea, luego destruir esa memoria, lo que implica mucho más trabajo que solo escanear un pequeño buffer deslizante, como lo hace 'grep'. – tadman

-2

usted debe leer en la memoria y luego analizar. Por supuesto, depende de lo que estás buscando. No hay que esperar un rendimiento milagro de rubí, sobre todo en comparación con c/C++ programas que se están optimizados para últimos 30 años ;-)

+0

es diferente del código que describí? –

+0

Su código se basa en Ruby tokenizer para leer el archivo y cederle el control después de cada línea, luego leer la siguiente línea y luego ceder nuevamente, etc. Mi sugerencia es leer un archivo completo en una memoria y tirar de él la información que necesita fuera – Zepplock

+0

Parece que intenta inundar el rendimiento c/C++, mal intento - el bucle es solo un bucle - todos los demás momentos importantes ya están cubiertos anteriormente –

Cuestiones relacionadas