2010-10-13 4 views
2

J'essaie d'améliorer les performances du rendu d'image captcha dans une application web fonctionnant sous Linux. En regardant ce qui est actuellement utilisé, j'ai trouvé que le goulot d'étranglement est dans l'utilisation de Java2D et en particulier de la classe Graphics2D.Comment rendre la génération d'image évolutive sur Java?

Le problème n'est pas tant avec la vitesse d'exécution qu'avec l'évolutivité. Fondamentalement, cela ne change pas. Le dessin d'images captcha dans 1 thread ou 2 threads n'apporte aucune amélioration en termes de temps d'exécution. Par exemple, vous pouvez jeter un oeil à la classe suivante qui crée un arrière-plan pour les images captcha. Le problème apparaît sur les appels à Graphics2D :: setColor() et Graphics2D :: drawLine():

http://www.docjar.com/html/api/com/octo/captcha/component/image/backgroundgenerator/FunkyBackgroundGenerator.java.html

Après quelques recherches sur Google et j'ai trouvé le sujet qui dit que Java2D est pas particulièrement bien avec le multi-threading (désolé , pas autorisé à donner plus d'un lien :) mais, vous pouvez facilement trouver ce sujet si google pour 'java2d multithreading', ce sera le premier résultat)

Je crois qu'il doit y avoir une bibliothèque qui fournit des capacités de dessin withtout en utilisant Java2d, mais n'a pas réussi à le trouver :(Ou Java2d, probablement, peut être commuté à un mode, qui ne bloque pas sur l'accès à l'objet graphique (btw, le mode sans tête ne aide pas).

J'apprécierai toutes les suggestions. Au préalable, merci pour les réponses.

+0

FWIW le premier coup que je reçois quand googler qui est sur l'écriture à la même objet graphics2D à partir de plusieurs threads. Pas à propos du cas où chacun a le sien. – wds

+0

http://forums.sun.com/thread.jspa?threadID=5415900 Voici une citation - "Après un peu de googling, j'ai trouvé cet article de quatre ans qui parle du pipeline OGL de java qui ne permet le rendu que sur un seul thread (à partir de Java 1.6). " – Stas

Répondre

1

Il n'y aura pas de moyen rapide de partager un Graphics2D qui fonctionne de manière prévisible car, à moins d'avoir un moyen de synchroniser et de réorganiser chaque pixel, ce serait une condition de concurrence massive.

Quoi qu'il en soit, votre Graphics2D est soutenu par un BufferedImage, c'est probablement ce qui vous ralentit. C'est une surface non accélérée donc le dessin sera toujours très lent. Si votre serveur de rendu a le matériel graphique pour cela (il devrait vraiment pour une application comme celle-ci), vous pouvez utiliser un VolatileImage qui est d'environ un ordre de grandeur ou deux plus rapide qu'un BufferedImage dans mon expérience.

Sinon, vous devrez découper votre génération d'arrière-plan en une grille, de manière à ce qu'elle s'aligne, rendre le "caractère aléatoire" commun à tous les éléments de la grille en l'ensemençant et en espérant que la méthode copyArea(...) est assez rapide pour vous net une amélioration. Je dirais presque que c'est un kludge et que le matériel accéléré est le chemin à parcourir.

Vous devez également envisager le pré-rendu d'un grand nombre d'entre eux en mode hors connexion et simplement en les servant au besoin. De cette façon, la performance est plus ou moins un problème, sauf si vous ne pouvez pas faire face à la demande pendant le temps d'inactivité des serveurs (dans ce cas, vous avez besoin d'un nouveau matériel et vous devez créer une boîte de rendu accélérée).

+0

Merci pour votre réponse et merci d'avoir été conseillé. Je vais essayer de les utiliser pour le rendre légèrement plus rapide. Mais jetez un oeil au code source, j'ai donné un lien vers. Ces méthodes qui sont appelées sur l'objet Graphics ne font rien d'autre que de placer un pixel coloré à l'emplacement. Accélérer une telle chose sur le matériel graphique semble risible. Un autre point est que le serveur tourne sur un serveur lame et je ne sais pas où même cette zone est localisée, c'est probablement même pas une boîte physique du tout. – Stas

+0

Solution idéale serait une bibliothèque qui peut travailler avec des images sans carte graphique du tout, mais a échoué en le trouver :( – Stas

+0

@Stas: VolatileImages sera généralement nettement plus rapide que BufferedImage même dans le cas de dessin au point en raison du fait qu'il est stockés dans la mémoire vidéo et tous les appels de dessin sont traduits dans les coulisses en appels accélérés par le matériel.Ne sous-estimez pas la rapidité avec laquelle les GPU modernes sont vraiment, surtout si setColor() et drawLine() sont vos goulots d'étranglement. des entailles qui représentent vos valeurs de couleur et voir si cela accélère les choses.Au minimum, il devrait être trivial de paralléliser –

0

Quelques idées d'optimisation basées sur un bref coup d'œil à votre code:

  • Vous créez une nouvelle BufferedImage pour chaque captcha. Je pense qu'il vaut mieux garder un BufferedImage et Graphics2D par thread dans les variables ThreadLocal et dessiner sur le captcha précédent quand vous en créez un nouveau
  • Vous faites une grande boucle sur chaque pixel avec beaucoup de calcul pour chaque pixel. Vous voulez absolument minimiser le calcul effectué au milieu de cette boucle, par ex. faire les calculs constants de "colorRightDown.getRed()/255.0f" etc.en dehors de la boucle
  • Envisagez de convertir tous les calculs à virgule flottante en maths entiers à virgule fixe équivalente. Ceci est généralement légèrement plus rapide à condition que vous puissiez tout faire rentrer dans les ints.
  • Utilisation BufferedImage.setRGB() avec des valeurs de couleurs entières plutôt que Graphics2D.setColor avec une nouvelle couleur - il sera beaucoup plus rapide et vous faire économiser beaucoup de pression GC
  • Voyez si vous pouvez réduire le nombre de hasard nombre d'appels par pixel, je compte 7 par pixel .... pouvez-vous sortir avec moins que cela? Vous feriez mieux de créer un entier aléatoire et de tester des sous-ensembles de bits.
  • Utilisez la largeur plutôt que getImageWidth() dans votre boucle interne (i), sinon vous appelez getImageWidth inutilement pour chaque pixel. Idem pour la boucle (j), même si cela compte beaucoup moins.

Je pense que ce qui précède combiné vous gagnerez beaucoup plus que de lancer des processeurs supplémentaires au problème :-) .....

Questions connexes