2010-08-15 17 views
5

J'ai un script qui, mis en opposition avec un timer, devient progressivement plus lent. C'est assez simple car tout ce qu'il fait est de lire une ligne, de la vérifier puis de l'ajouter à la base de données, puis de passer à la ligne suivante.Le script PHP devient progressivement plus lent (lecteur de fichier)

est ici la sortie de celui-ci se aggrave progressivement:

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 

Le fichier, malheureusement, est d'environ ~ 20gb donc je serai probablement mort au moment où la chose est lu au taux d'augmentation. Le code est (principalement) ci-dessous mais je soupçonne que c'est quelque chose à voir avec fgets(), mais je ne sais pas quoi.

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

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

     save_record ($data, $line); 
    } 

Merci d'avance!

EDIT:

Décommenter 'save_record ($ data, ligne de $);' semble ne rien faire.

+0

Pouvez-vous écrire le code pour save_record? C'est probablement la clé – Jhong

+0

En fait, si je commente la ligne save_record() c'est toujours aussi mauvais. – DCD

+1

Comment obtenez-vous cette sortie de performance? Vous n'avez pas de journalisation des performances dans l'exemple de code que vous avez fourni. Je soupçonne que le problème est ailleurs. Avez-vous plus de code que vous ne nous montrez pas qui pourrait être pertinent? –

Répondre

0

Bon, un problème de performance. Évidemment, quelque chose devient quadratique quand il ne devrait pas, ou plus exactement, quelque chose qui devrait être constant - le temps semble être linéaire dans le nombre de dossiers traités jusqu'à présent. La première question est de savoir quel est le morceau de code minimal qui présente le problème. Je voudrais savoir si vous obtenez le même comportement problématique lorsque vous commentez tout sauf lire le fichier ligne par ligne. Si oui, alors vous aurez besoin d'une langue sans ce problème. (Il y en a beaucoup.) Quoi qu'il en soit, une fois que vous voyez la caractéristique de temps prévu, ajoutez les déclarations une par une jusqu'à ce que votre timing devienne hawwire, et vous aurez identifié le problème.

Vous avez instrumenté quelque chose ou autre pour obtenir les timings. Assurez-vous que ceux-ci ne peuvent causer de problème en les exécutant seuls 15 000 fois.

1

Il est parfois préférable d'utiliser les commandes système pour lire ces fichiers volumineux. Je suis tombé sur quelque chose de similaire et est un petit truc ici je:

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

Je ne recommanderais pas cela avec des fichiers qui ne peuvent pas faire confiance, mais il court vite, car il tire un enregistrement à la fois à l'aide du système. J'espère que cela t'aides.

+0

+1 bonne idée, je vais considérer cela dans le futur. – alex

0

J'ai trouvé cette question en essayant de trouver un moyen pour moi de passer plus rapidement à travers un fichier texte de 96G. Le script que j'ai écrit initialement a pris 15 heures pour atteindre 0.1% ...

J'ai essayé certaines des solutions suggérées ici, en utilisant stream_get_line, fgets et exec pour sed. Je me suis retrouvé avec une approche différente que je pensais partager avec quelqu'un d'autre qui s'arrête sur cette question.

Diviser le fichier! :-)

Sur ma boîte freebsd (existe aussi pour linux et autres), j'ai un utilitaire de ligne de commande nommé '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]] 

Je couru:

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

Alors j'ai fini avec 5608 fichiers dans le répertoire/data/var/monfichier-log/répertoire, ce qui pourrait alors tous être traités un à la fois avec une commande comme:

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