2010-08-15 4 views
5

Tengo un script que, cuando se compara con un temporizador, se vuelve progresivamente más lento. Es bastante simple, ya que todo lo que hace es leer una línea, verifica y luego la agrega a la base de datos, luego pasa a la siguiente línea.El script PHP se vuelve progresivamente más lento (lector de archivos)

Aquí está la salida de la misma empeorando poco a poco:

Record: #1,001 Memory: 1,355,360kb taking 1.84s 
Record: #1,001 Memory: 1,355,360kb taking 1.84s 
Record: #2,002 Memory: 1,355,192kb taking 2.12s 
Record: #3,003 Memory: 1,355,192kb taking 2.39s 
Record: #4,004 Memory: 1,355,192kb taking 2.65s 
Record: #5,005 Memory: 1,355,200kb taking 2.94s 
Record: #6,006 Memory: 1,355,376kb taking 3.28s 
Record: #7,007 Memory: 1,355,176kb taking 3.56s 
Record: #8,008 Memory: 1,355,408kb taking 3.81s 
Record: #9,009 Memory: 1,355,464kb taking 4.07s 
Record: #10,010 Memory: 1,355,392kb taking 4.32s 
Record: #11,011 Memory: 1,355,352kb taking 4.63s 
Record: #12,012 Memory: 1,355,376kb taking 4.90s 
Record: #13,013 Memory: 1,355,200kb taking 5.14s 
Record: #14,014 Memory: 1,355,184kb taking 5.43s 
Record: #15,015 Memory: 1,355,344kb taking 5.72s 

El archivo, por desgracia, es de alrededor de ~ 20 GB, así que probablemente estará muerto para el momento en todo el asunto se lee en la tasa de aumento. El código está (principalmente) a continuación, pero sospecho que tiene algo que ver con fgets(), pero no estoy seguro de qué.

$handle = fopen ($import_file, 'r'); 

    while ($line = fgets ($handle)) 
    { 
     $data = json_decode ($line); 

     save_record ($data, $line); 
    } 

¡Gracias de antemano!

EDIT:

Comentando 'save_record ($ data, $ línea);' parece no hacer nada.

+0

¿Se puede publicar el código de save_record? Esa es probablemente la clave – Jhong

+0

En realidad, si comento la línea save_record() sigue igual de mal. – DCD

+1

¿Cómo está obteniendo ese rendimiento de rendimiento? No tiene registro de rendimiento en la muestra de código que proporcionó. Sospecho que el problema está en otra parte. ¿Tiene algún otro código que no nos muestra que pueda ser relevante? –

Respuesta

0

bien, un problema de rendimiento. Obviamente, algo se vuelve cuadrático cuando no debería, o más al punto, algo que debería ser constante; el tiempo parece ser lineal en el número de registros tratados hasta ahora. La primera pregunta es cuál es la cantidad mínima de código que muestra el problema. Me gustaría saber si obtienes el mismo comportamiento problemático cuando comentas todo pero lees el archivo línea por línea. Si es así, entonces necesitarás un idioma sin ese problema. (Hay muchos). De todos modos, una vez que vea la característica de tiempo esperada, agregue las declaraciones una por una hasta que su tiempo se descontrole, y habrá identificado el problema.

Ha instrumentado una u otra cosa para obtener los tiempos. Asegúrese de que no puedan causar un problema ejecutándolos solos 15000 veces más o menos.

1

A veces es mejor utilizar los comandos del sistema para leer estos archivos de gran tamaño. Me encontré con algo similar y aquí es un pequeño truco que utilicé:

$lines = exec("wc -l $filename"); 
for($i=1; $i <= $lines; $i++) { 
    $line = exec('sed \''.$i.'!d\' '.$filename); 

    // do what you want with the record here 
} 

no recomendaría esto con archivos que no se puede confiar, pero su ejecución es rápida ya que tira de un registro a la vez que utiliza el sistema. Espero que esto ayude.

+0

+1 buena idea, lo consideraré en el futuro. – alex

0

Encontré esta pregunta al tratar de encontrar una manera de pasar más rápido a través de un archivo de texto 96G. La secuencia de comandos que inicialmente escribí tomó 15 horas para llegar a 0.1% ...

He intentado algunas de las soluciones sugeridas aquí, usando stream_get_line, fgets y exec for sed. Terminé con un enfoque diferente que pensé que compartiría con cualquiera que se detuviera con esta pregunta.

¡Divida el archivo! :-)

En mi casilla freebsd (también existe para Linux y otros) tengo una utilidad de línea de comandos llamada 'split'.

 
usage: split [-l line_count] [-a suffix_length] [file [prefix]] 
     split -b byte_count[K|k|M|m|G|g] [-a suffix_length] [file [prefix]] 
     split -n chunk_count [-a suffix_length] [file [prefix]] 
     split -p pattern [-a suffix_length] [file [prefix]] 

por lo que corrí:

 
split -l 25000 -a 3 /data/var/myfile.log /data/var/myfile-log/ 

Entonces terminamos con 5608 archivos en el directorio/var/mi_archivo-log/directorio/datos, que podría entonces todo ser procesados ​​uno a la vez con un comando como:

 
php -f do-some-work.php /data/var/myfile-log/* 
Cuestiones relacionadas