6 votes

Faibles performances avec BufferedReader

Je traite un certain nombre de fichiers texte ligne par ligne en utilisant BufferReader.readlLine() .

Deux fichiers ayant la même taille 130MB mais l'un prend 40sec pour être traité alors que l'autre prend 75sec.

J'ai remarqué qu'un fichier contient 1,8 million de lignes et un autre 2,1 millions. Mais lorsque j'ai essayé de traiter un fichier de 3 millions de lignes de même taille, le traitement a pris 30 minutes.

Donc ma question est :

  1. Est-ce que ce comportement est dû au temps de recherche du lecteur de mémoire tampon (je veux savoir comment le lecteur de mémoire tampon fonctionne) ? BufferedReader fonctionne ou analyse le fichier ligne par ligne ?)

  2. Existe-t-il un moyen de lire le fichier ligne par ligne de manière plus rapide ?

Ok les amis, je vous donne quelques détails supplémentaires.

Je divise la ligne en trois parties à l'aide d'une expression rationnelle, puis j'utilise la méthode suivante SimpleUnsortedWriter (fourni par Cassandra) Je l'écris dans un fichier en tant que clé, colonne et valeur. Après le traitement des 16 Mo de données, elles sont effacées sur le disque.

Mais la logique de traitement est la même pour tous les fichiers, même un fichier d'une taille de 330MB mais avec moins de lignes, environ 1 million, est traité en 30 secondes. Quelle pourrait être la raison ?

deviceWriter = new SSTableSimpleUnsortedWriter(
        directory,
        keyspace,
        "Devices",
        UTF8Type.instance,
        null,
        16);

Pattern pattern = Pattern.compile("[\\[,\\]]");
while ((line = br.readLine()) != null)          
{
    //split the line i n row column and value
    long timestamp = System.currentTimeMillis() * 1000;
    deviceWriter .newRow(bytes(rowKey));
    deviceWriter .addColumn(bytes(colmName), bytes(value), timestamp);

}

Ont changé -Xmx256M to -Xmx 1024M mais ça ne sert à rien de toute façon.

Mise à jour : D'après mes observations, lorsque j'écris dans un tampon (dans la mémoire physique), le nombre d'écritures dans un tampon augmente et les nouvelles écritures prennent du temps. (C'est mon hypothèse)

Veuillez répondre.

5voto

Michael Borgwardt Points 181658

La seule chose BufferedReader est lu à partir de la base de données Reader dans un char[] avec une taille par défaut de 8K, et toutes les méthodes travaillent sur ce tampon jusqu'à ce qu'il soit épuisé, auquel cas un autre 8K (ou autre) est lu à partir de la mémoire tampon sous-jacente. Reader . El readLine() est en quelque sorte plaquée.

Utilisation correcte de BufferedReader doit absolument no Le résultat est que le temps de fonctionnement passe de 40 secondes pour 1,8 millions de lignes à 30 minutes pour 3 millions de lignes. Il doit y avoir un problème avec votre code. Montrez-le nous.

Une autre possibilité est que votre JVM n'a pas assez de mémoire de tas et passe la plupart des 30 minutes à faire du garbage collection parce que son tas est plein à 99% et vous obtiendriez éventuellement un OutOfMemoryError avec une entrée plus importante. Que faites-vous avec les lignes que vous avez traitées ? Sont-elles conservées en mémoire ? Est-ce que l'exécution du programme avec le -Xmx 1024M fait-elle une différence ?

1voto

Simone Gianni Points 4009

BufferedReader ne cherche pas, il met simplement en cache les caractères jusqu'à ce qu'une nouvelle ligne soit trouvée et renvoie la ligne sous forme de chaîne, en supprimant (réutilisant) le tampon après chaque ligne. C'est pourquoi vous pouvez l'utiliser avec n'importe quel flux ou autre lecteur, même ceux qui ne supportent pas la recherche.

Ainsi, le nombre de lignes à lui seul ne devrait pas créer une si grande différence au niveau du lecteur. Une très longue ligne pourrait cependant créer une très grande chaîne et une allocation de beaucoup de RAM, mais cela ne semble pas être votre cas (dans ce cas, il y aurait probablement une exception OutOfMemory pour excès de temps GC ou similaire).

Pour ce que je peux voir dans votre code, vous ne faites rien de mal. Je suppose que vous vous heurtez à une sorte de limite, puisqu'il ne semble pas s'agir de la RAM. Peut-être cela a-t-il quelque chose à voir avec une limite stricte du côté de Cassandra ? Avez-vous essayé de commenter la partie qui écrit sur Cassandra ? juste pour voir si c'est votre côté ou celui de Cassandra qui cause le problème.

1voto

Farmor Points 4928

Regardez dans NIO Buffered car ils sont plus optimisés que BufferReader.

Quelques extraits de code provenant d'un autre forum. http://www.velocityreviews.com/forums/t719006-bufferedreader-vs-nio-buffer.html

FileChannel fc = new FileInputStream("File.txt").getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
fc.read(buffer);

Edit : Regardez aussi ce fil de discussion Lire des fichiers volumineux en Java

1voto

erickson Points 127945

El BufferedReader n'est probablement pas la racine de votre problème de performance.

D'après les chiffres que vous citez, il semble que votre code présente une complexité quadratique. Par exemple, pour chaque ligne que vous lisez, vous réexaminez toutes les lignes que vous avez lues précédemment. Je ne fais que spéculer ici, mais un exemple courant du problème serait d'utiliser une structure de données de type liste, et de vérifier si la nouvelle ligne correspond aux lignes précédentes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X