2016-07-27 1 views
0

Ce n'est pas la première fois que je rencontre ce problème. J'optimise mon code Scala/Java en examinant les enregistrements Flight Recorder dans Java Mission Control. Regardez les méthodes les plus chaudes, puis les allocations de mémoire, et finalement l'application s'exécute 50 fois plus vite, ou 3 fois plus vite. Une fois arrivé à ce point, l'utilisation du processeur est de 60 à 90% et l'utilisation de la mémoire est par exemple de 2 Go sur le tas de 4 Go maximum. Pourtant, je pense que je pourrais faire beaucoup plus de vitesse.Optimisation des performances de l'application Java (traitement des données vanilla)

Caractéristiques:

  • traitement de fil à l'unité, à la lecture d'un seul fichier à partir du système de fichiers.
  • Lecture séquentielle où la vitesse de lecture du système de fichiers est de 1 Go/s, mais le traitement est aussi lent que 5 Mo/s (branchement, machines à états, etc.).
  • Minimisé les collections de déchets où je pouvais.
  • Pas de bibliothèques sophistiquées, juste du code JVM pur.

code ressemble à peu près comme celui-ci (en pseudocode):

for line in file // using an iterator which would call into a file 
    result = process_line(line) 
    state = state.process(result) 
    if state.emits: 
    println(state.result) 

Dans une application je les méthodes les plus chaudes suivantes:

scala.collection.immutable.HashMap$HashTrieMap.getO(Object, Int, Int) 6.75% 
java.io.BufferedInputStream.read() 4.97% 

Dans un autre (ce qui est du haut de ma tête):

(some sort of garbage collection process) 9% 
...  7% 

Est-ce encore la peine d'opter en les imitant? J'ai essayé, et gagné très peu d'amélioration de la performance pour un code beaucoup plus complexe.

Où devrais-je regarder ensuite?

Dois-je envisager de créer process_line() sur un thread, puis d'itérer l'état sur un autre thread afin de minimiser le changement de contexte? Peut-être que c'est ce qui ralentit les choses?

Quelle est la bonne façon de procéder? Je ne veux pas paralléliser le problème lui-même pour le moment.

+1

Je voudrais mettre l'accent sur où vous passez le plus de temps en utilisant le processeur et voir si vous pouvez l'optimiser ou passer le travail à un autre thread. C'est à dire. vous vous dirigez dans la bonne direction, vous devez continuer à optimiser. –

+0

J'ai mis à jour la question pour inclure un peu plus de détails. Il n'y a pas de méthode 'la plus chaude', il y a un tas de différents paquets utilisant une quantité de CPU similaire. –

+1

Je serais méfiant d'une collection triée comme vous avez et voyez si vous pouvez écrire le code sans elle. BufferedInputStream.read() ne devrait pas être si cher qu'il devrait lire le blocage des octets à la fois idéalement, mais cela dépend de pourquoi vous faites cela. Je voudrais regarder combien de méthodes sont les opérations de collecte esp "bruit", et non la logique de base de ce que fait votre application. –

Répondre

0

Je voudrais paralléliser le lecteur. Si les données sont sur le disque, vous pouvez créer un thread qui lit les données du disque dans les morceaux et un autre qui le traite. C'est, en passant, comment Java Mission Control 4 lit les fichiers d'enregistrement. Ou vous pourriez faire comme Java Mission Control 5, qui utilise un RandomAccessFile qu'il lit à partir de plusieurs threads, puis le résultat est assemblé.