2010-08-15 18 views
5

Ho uno script che, quando messo contro un timer, diventa progressivamente più lento. È abbastanza semplice poiché tutto ciò che fa è leggere una riga, controllarla, quindi aggiungerla al database, quindi passare alla riga successiva.Lo script PHP diventa progressivamente più lento (lettore di file)

ecco l'output di esso via via peggiorando:

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 

Il file, purtroppo, è di circa ~ 20GB così io probabilmente essere morto per il momento il tutto è letto sul tasso di aumento. Il codice è (principalmente) sotto, ma ho il sospetto che abbia qualcosa a che fare con fgets(), ma non sono sicuro di cosa.

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

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

     save_record ($data, $line); 
    } 

Grazie in anticipo!

EDIT:

Commentando out 'save_record ($ dati, $ linea);' sembra non fare nulla.

+0

Puoi pubblicare il codice per save_record? Questa è probabilmente la chiave – Jhong

+0

In realtà se commento la riga save_record() è ancora così male. – DCD

+1

Come stai ottenendo quell'output di prestazioni? Non hai alcuna registrazione delle prestazioni nell'esempio di codice che hai fornito. Sospetto che il problema sia altrove. Avete qualche altro codice che non state mostrando che potrebbe essere rilevante? –

risposta

0

Va bene, un problema di prestazioni. Ovviamente qualcosa sta diventando quadratico quando non dovrebbe, o più al punto, qualcosa che dovrebbe essere costante-tempo sembra essere lineare nel numero di documenti trattati finora. La prima domanda è qual è il minimo frammento di codice che mostra il problema. Vorrei sapere se si ottiene lo stesso comportamento problematico quando si commenta tutto ma leggendo il file riga per riga. Se è così, allora avrai bisogno di una lingua senza quel problema. (Ce ne sono molte). Ad ogni modo, una volta che vedi le caratteristiche del tempo atteso, aggiungi le dichiarazioni indietro una alla volta finché il tuo tempismo non va in tilt, e avrai identificato il problema.

Hai strumentato qualcosa o altro per ottenere i tempi. Assicurati che quelli non possano causare problemi eseguendoli da soli 15000 volte o giù di lì.

1

A volte è meglio usare i comandi di sistema per leggere questi file di grandi dimensioni. Mi sono imbattuto in qualcosa di simile ed ecco un piccolo trucco che ho usato:

$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 
} 

non consiglierei questo con i file che non si può fidare, ma corre veloce dal momento che tira un record alla volta utilizzando il sistema. Spero che questo ti aiuti.

+0

+1 buona idea, lo prenderò in considerazione in futuro. – alex

0

Ho trovato questa domanda mentre cercavo di trovare un modo per passare più rapidamente a un file di testo 96G. La sceneggiatura che avevo inizialmente scritto impiegava 15 ore per raggiungere lo 0,1% ...

Ho provato alcune delle soluzioni suggerite qui, utilizzando stream_get_line, fgets ed exec per sed. Ho finito con un approccio diverso che pensavo di condividere con chiunque altro fermandosi a questa domanda.

Suddividi il file! :-)

Nella mia casella freebsd (esiste anche per linux e altri) ho un'utilità della riga di comando denominata '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]] 

così mi sono imbattuto:

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

Poi ho finito con 5608 file nella directory/var/myfile-log/directory/dati, che potrebbe poi essere tutti elaborati uno alla volta con un comando Mi piace:

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