IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

avec Java Discussion :

Construction d'une image pixel par pixel en multi-threads


Sujet :

avec Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Inscrit en
    Juin 2011
    Messages
    258
    Détails du profil
    Informations forums :
    Inscription : Juin 2011
    Messages : 258
    Par défaut Construction d'une image pixel par pixel en multi-threads
    Bonjour à vous,

    J'ai récemment créé un petit moteur de rendu de scène 3D. De base, il n'utilisait pas de threads supplémentaires.

    Le traitement (la génération de l'image) prend ~2.5s. Je me suis donc dit que je pourrais essayer d'accélérer un peu tout ça en multi-threads (sur un core i7 920 d0 (4 cores physiques, 4 logiques)).

    Le résultat: le programme met ~4.3s à l'exécution, mon implentation de threads l'a beaucoup ralentie. Je ne comprends pas bien pourquoi.

    L'algorithme sans ajout de threads:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    for (int i = 0; i < hauteurImage; i++) {
         for (int j = 0; j < largeurImage; j++) {
            //calcul de la couleur du pixel
            //traitement de la couleur du pixel (pour le out of gamma)
            //affichage du pixel
            fenetre.getGraphics.setColor(couleurCalculee);
            fenetre.getGraphics.fillRect(ligne, colonne, 1, 1);
        }
    }
    Et en multi-threads:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    //déclaration de x threads, où x = Runtime.getRuntime().availableProcessors();
    for (int i = 0; i < hauteurImage; i++) {
         for (int j = 0; j < largeurImage; j++) {
            Thread truc = listeThreads.get(j%x); //thread correspondant au pixel en cours
            truc.join(); //attendre le traitement précédent du thread
            truc.start(); //calcul du pixel puis affichage de celui-ci, de la même méthode qu'en simple thread
        }
    }
    J'ai aussi essayé en créant un thread temporaire par calcul de pixel, mais les résultats sont les mêmes.

    Au final, les threads calculent un thread sur x, où x est le nombre de coeurs disponibles (ici 8, testé avec 4 aussi, mêmes résultats).

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Salut,

    ton join() fait que à chaque itération(), tu attends que ton thread soit terminé, donc en réalité tu n'est pas en multithread.

    tu devrais essayer de gérer plutôt ça par un système de pool de thread : à chaque itération tu empile un ordre de calcul de point, ton pool étant chargé de paralléliser les traitement.

    regarde l'api java.util.concurent

    par exemple...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    public class DessineImage {
     
      public final Fenetre fenetre;
     
      public DessineImage(int hauteurImage, int largeurImage, Fenetre fenetre) {
        this.fenetre=fenetre;
     
        ExecutorService service = Executors.newFixedThreadPool(10/*nombre de threads*/);
     
        for (int i = 0; i < hauteurImage; i++) {
          for (int j = 0; j < largeurImage; j++) {
          	service.execute(new CalculPoint(j,i));
          }
        }
     
        service.shutdown();
      }
     
      public class CalculPoint implements Runnable {
     
        private final int colonne;
        private final int ligne;
     
        public CalculPoint(int colonne, int ligne) {
          this.colonne=colonne;
          this.ligne=ligne;
        }
     
        @Override
        public void run() {
            //calcul de la couleur du pixel
            //traitement de la couleur du pixel (pour le out of gamma)
            //affichage du pixel
            fenetre.getGraphics().setColor(couleurCalculee);
            fenetre.getGraphics().fillRect(ligne, colonne, 1, 1);
     
        }
      }
     
    }
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre éclairé
    Inscrit en
    Juin 2011
    Messages
    258
    Détails du profil
    Informations forums :
    Inscription : Juin 2011
    Messages : 258
    Par défaut
    Bonsoir et merci de ta réponse.

    eclesia m'a conseillé d'utiliser ceci aussi. Je l'ai donc implanté, l'exécution prend maintenant ~12 secondes. :/ Il m'a conseillé de regarder le temps d'exécution des méthodes, ce que je vais faire.

    Concernant le join, en fait j'avais plusieurs threads, donc j'attendais seulement le thread qui était sensé calculer le pixel (je fais un .get sur une liste de threads précédemment déclarés).

  4. #4
    Membre éclairé
    Inscrit en
    Juin 2011
    Messages
    258
    Détails du profil
    Informations forums :
    Inscription : Juin 2011
    Messages : 258
    Par défaut
    Je viens aux nouvelles, j'avais laissé des centaines d'exécutions de System.out.println, d'où le temps d'exécution. Au final, le temps d'exécution passe à ~2.5s.

    Soit environ le même temps qu'en simple thread. Les changements dans Graphics puis son affichage semble être le "souci" étant donné qu'une instruction seulement ne peut être faite en même temps. Bref, il va à priori falloir queje me débarasse de graphics.

  5. #5
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    il y a plusieurs choses à considérer :

    - déjà les threads java ne sont pas des threads système mais des threads simulés dans la jvm : donc il y a un temps de partage.
    tu peux éventuellement modifier la fabrique de thread pour modifier la priorité d'exécution de tes threads

    - toute introduction de méthodes intermédiares introduit des temps de traitement en particulier pour la gestion de la pile

    - l'instanciation des Runnable introduit un temps non négligable : on peut résoudre ça par un pool par exemple

    - après il faut regarder comment est implémenté ton setColor et ton fillRect
    tu peux éventuellement dessiner ton point par manipulation d'octet probablement plus rapide que les méthodes de dessin de la classe Graphics2D


    - il faut mettre en opposition le temps de traitement unitaire de tes pixels et le temps introduit par l'introduction de thread : peut être que faire un thread par ligne serait plus efficace, ou découper ton image en bloc
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  6. #6
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    pour les threads simulés, je me suis mal exprimé, les threads java sont mappés sur des threads natifs, mais ce sont pas des threads natifs, dans le sens ou il y a une surcouche de gestion interne qui introduit nécessairement un temps des gestion. maintenant il est peut probablement de gagner tant que ça en implémentant des threads complètement natif, sauf en introduisant la gestion de l'affinité de manière à optimiser la répartition sur les différents processeurs
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  7. #7
    Membre éclairé
    Inscrit en
    Juin 2011
    Messages
    258
    Détails du profil
    Informations forums :
    Inscription : Juin 2011
    Messages : 258
    Par défaut
    Merci pour toutes ses informations, ça me sera très utile.

    Je vais faire des tests, tenter des blocs de pixel par thread, l'instanciation doit prendre un certain temps en effet, pour une image de 400x400 ça me faisait 160 000 instanciations d'objet runnable.

    Edit: par bloque de pixel ça reste au même temps d'exécution, je vais voir pour essayer de changer l'affichage, peut-être stocker l'image entière et l'afficher d'un coup au lieu d'appeler x fois fillRect & setColor, et si ça ne fonctionne pas mieux, voir pour trouver un autre moyen d'afficher l'image

  8. #8
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par garheb Voir le message
    Merci pour toutes ses informations, ça me sera très utile.

    Je vais faire des tests, tenter des blocs de pixel par thread, l'instanciation doit prendre un certain temps en effet, pour une image de 400x400 ça me faisait 160 000 instanciations d'objet runnable.
    ça peut compter, mais bon 160000 instanciations,ça doit prendre peanuts (sur mon vieux pc pourri hyper lent (atom sous xp c'est pour dire), je viens de tester : 15ms) par rapport à 2,5s, mais bon, additionnées des ms, ça peut compter,

    essayer de voir si tu peux pas optimiser tes calculs aussi (factoriser par exemple, précalculer, etc)
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Import d'une image PNG par pixel
    Par LudoParis dans le forum VB.NET
    Réponses: 7
    Dernier message: 12/12/2011, 19h47
  2. Image a remplir Pixel par Pixel, Quel objet utiliser ?
    Par ZbergK dans le forum GTK+ avec C & C++
    Réponses: 5
    Dernier message: 28/02/2007, 21h35
  3. [ImageMagick] Parcourir une image pixel par pixel
    Par kip dans le forum Bibliothèques et frameworks
    Réponses: 1
    Dernier message: 05/10/2005, 14h10
  4. [VB6] [Graphisme] Transfert d'image pixel par pixel
    Par SpaceFrog dans le forum VB 6 et antérieur
    Réponses: 16
    Dernier message: 15/10/2002, 09h53

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo