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

Java Discussion :

optimiser un traitement par du multi-threading


Sujet :

Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    in
    in est déconnecté
    Membre Expert Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Par défaut optimiser un traitement par du multi-threading
    Bonjour,

    j'espère que je m'engage dans la bonne voie. En fait j'ai un traitement qui est très long. J'ai réussi à cibler le morceau qui est le plus lent et j'aimerais l'exécuter en multi-thread. Par contre en lisant un peu de doc, je ne fais que m'embrouiller j'ai l'impression.

    j'ai donc besoin de vos lumières. Voici "en gros" le code existant. les // indiquent quelle partie je voudrais paralléliser.

    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
    boucle 1 {
    
           ObjetType1 obj ...
    
           ObjetType2[] listeObjetType2 = obj.loadListeType2
           
    
           boucle 2 {   // boucle for sur listeObjetType2
    
    // début parallèle
                      ObjetType3 o3 = listeObjetType2[i].chargeType3();
                      // hop des traitements (lectures de valeurs sur o3)
                      // ajout des valeurs dans un objet hashmap  (à transformer en hashtable je suppose ??)
                     listeCumulée.add(/* les valeurs que j'ai lues précédemment*/);
                     // si la clé existe déjà, on cumule les valeurs
    // fin parallèle
           } // boucle 2
    
           // traitement sur l'objet listeCumulée et vidage de la liste
    
    } // boucle 1
    bon j'espère que c'est clair ...

    En fait j'ai deux questions :

    1 . comment exécuter un thread par indice de boucle ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for(...)  //boucle2
    new Thread { public void run() { /* mon code à paralléliser */ }};
    faut il fermer le thread apres ou c'est automatique.

    2 . mon objet listeCumulée (un hashmap pour l'intant) doit il etre transformé en hashtable ? Faut il que j'y accède en synchronised.
    Sur cet objet, quand je fais add, je vérifie si la clé existe, si oui, je cumule la valeur existante. Est ce que le multi-thread ne va pas alourdir mon traitement au lieu de l'améliorer ??


    merci d'avance et désolé pour la longueur ...


    [EDIT] petite question subsidiaire ...
    dans ce traitement à paralléliser, lorsque je catch une exception, j'écris dans un fichier de log. Faut il également utiliser le mot clé synchronised ? (je suppose que oui mais bon, je suis un peu embrouillé ... on serait pas lundi matin ?? )

  2. #2
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,

    Citation Envoyé par in
    1 . comment exécuter un thread par indice de boucle ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for(...)  //boucle2
    new Thread { public void run() { /* mon code à paralléliser */ }};
    Tu peux définir une variable locale final afin de pouvoir passer la valeur à ton thread, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
            for (int i = 0; i<5; i++) {
                final int index = i;
                new Thread() {
                    public void run() {
                        System.out.println("Index = " + index);
                    }
                }.start();
            }
    Citation Envoyé par in
    faut il fermer le thread apres ou c'est automatique.
    Non. Les threads se finissent dès la fin de leur méthode run().


    Citation Envoyé par in
    2 . mon objet listeCumulée (un hashmap pour l'intant) doit il etre transformé en hashtable ? Faut il que j'y accède en synchronised.
    Tu as trois solutions :
    • Utiliser un hashtable (solution la moins propre à mon avis).
    • La synchroniser avec Collections.synchronizedMap()
    • La synchroniser manuellement. Dans ton cas (et si j'ai bien compris), tu hérites de HashMap en définissant add() qui ajoute les données selon certaines règles. Si c'est bien la seule méthode qui sera directement appellé dans les threads tu peux te contenter de synchroniser cette méthode...
    Citation Envoyé par in
    Est ce que le multi-thread ne va pas alourdir mon traitement au lieu de l'améliorer ??
    Ca dépend de l'origine exact de la lourdeur du traitement...
    Le coût de la synchronisation en elle même ne sera pas vraiment un problème... Par contre si le traitement synchronisé est long les autres threads risqueront de se retrouver en attente du verrou un peu trop longtemps...

    Evite également de créer un trop gros nombres de thread... cela ne sert à rien de faire 500 threads !!! Tu peux utiliser la classe Executors de Java 5.0 qui permet d'utiliser des pools de threads...




    merci d'avance et désolé pour la longueur ...


    Citation Envoyé par in
    [EDIT] petite question subsidiaire ...
    dans ce traitement à paralléliser, lorsque je catch une exception, j'écris dans un fichier de log. Faut il également utiliser le mot clé synchronised ?
    Java IO est synchronisé... mais tu auras quand même besoin de gérer une synchronisation

    Je m'explique : chaque écriture est bien synchronisé et ne risque pas de se retrouver tronquée... mais indépendamment les uns des autres... C'est à dire que si tu fais deux opérations d'écriture successive, rien ne garantit que rien ne viendra s'insérer entre les deux...

    Pour éviter cela il faut synchronisé en utilisant l'OutpuStream ou le Reader, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    synchronized(System.out) {
          System.out.println("Ligne 1");
          System.out.println("Ligne 2");
    }
    a++

  3. #3
    in
    in est déconnecté
    Membre Expert Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Par défaut
    Merci de ta réponse ... pendant que j'y suis je suis en 1.4

    alors ouais j'utilise des variables finales dans la boucle. Ca c'est ok.

    par contre, je dois attendre que tous les threads soient terminés avant de poursuivre le traitement. donc je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Thread[] threads = new Thread[monTab.length]
    for( monTab ) {
     
        threads[i] = new Thread{ public vois run() {/* mon code qui va bien */} };
     
    }
     
    for (threads)
       threads[i].start();
     
    for (threads)
       threads[i].join();
    ce qui ne me parait pas très propre.

    Ca à l'air de fonctionner en tous cas ... mais quand mon tableau est trop gros, (genre 50) l'API que j'utilise ne tient pas la route (exception : System busy ...). Je pense que c'est à cause des connexions à la bdd.

    Donc 2 sol° soit un pool, soit faire moins de threads. Je n'arrive pas trop à me décider ... je pense que je vais essayer de faire moins de threads à la fois (genre 10 par 10)


    Pour la hashmap, j'ai donc mis synchronized sur la méthode add. Idem pour l'écriture dans le log.


    Bref, j'y retourne

    merci en tous cas. je te tiens au courant de ma progression. Et n'hésite pas si tu as des remarques ...

  4. #4
    in
    in est déconnecté
    Membre Expert Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Par défaut
    Bon, ça à l'air quasi presque utilisable ...

    le pb est au niveau de l'attente de terminaison qui n'est pas (du tout) top.

    je limite le nb de threads en cours à 10 (pour test). Je fais donc :

    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
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    // pour des problèmes de temps de traitements 5.3
    Thread[] thread = new Thread[10];
    int nbEnCours = 0;
     
    for(int i=0; i<listeOID.length; i++){
     
    	final ObjectId oid = listeOID[i];
    	final Integer epsT = epsId;
    	final Integer projT = projId;
    	final Integer actT = actId;
     
    	if(++nbEnCours == 10){
    		print("lancement de 10 threads");
    		for(int j=0; j<thread.length; j++){
    			if(thread[j] != null)
    				thread[j].start();
    		}
     
    		// on attend que les threads soient terminés
    		for(int j=0; j<thread.length; j++){
    			print("Attente terminaison threads");
    			try {
    				if(thread[j] != null)
    			                thread[j].join();
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    			print("Terminé");
    		}
     
    		nbEnCours = 0;
    		}
     
    		thread[nbEnCours] = new Thread(){
    				public void run(){
     
                                         // des traitements en veux tu en voilà
    				     listeValeurs.add(new LigneCharge(epsT, projT, actT, resId,period),new Double[]{remainingUnits,actualUnits});	
                                    }};
     
    }// fin parcours ResourceAssignment
     
    // tableau de threads initialisé
    for(int i=0; i<thread.length; i++){
    	if(thread[i] != null && !thread[i].isAlive())
    		thread[i].start();
    }
     
    // on attend que les threads soient terminés
    for(int i=0; i<thread.length; i++){
    	try {
    		if(thread[i] != null)
    			thread[i].join();
    	} catch (InterruptedException e) {
    		e.printStackTrace();
    	}
    }
    par contre l'attente de terminaison se fait Thread par Thread. Je ne peux pas attendre "activement" tous les threads. Est ce que passer par un threadGrour résoudrait ce problème ?

    Y a t'il des best pratices à respecter ?

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    75
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 75
    Par défaut
    Salut,

    Pour l'attente de terminaison de tes threads tu devrais peut être utiliser le principe du "publieur/consommeur" :
    Tu fais par exemple un pile (ou un compteur) synchroniser dans laquel tu mets tes taches ou un indicateur de ces taches, chaque thread correspondant à une d'entre elle.
    Quand un thread commence un traitement il s'ajoute (ou augmente ton compteur) à ta pile, quand il a finit il se "libere" de celle ci (bien synchroniser les méthodes ou objets qui font cela).

    Ta classe qui lance tout cela fait une attente "passive" sur ta pile (un while(...) {... wait();}... et de l'autre côtés un notify...) jusqu'a ce que la pile soit vide (donc que le traitement sont finit).

    Je ne sais pas si j'ai été bien clair (en faite je ne crois).

    Si par contre tu es en 1.5 regarde la classe ThreadPoolExecutor, elle devrait grandement te simplifier la vie.

    Louis

  6. #6
    in
    in est déconnecté
    Membre Expert Avatar de in
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    1 612
    Détails du profil
    Informations personnelles :
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 612
    Par défaut
    ben oui j'ai essayé un truc comme ça mais bon, c'est pareil, j'attend la terminaison d'un thread à la fois.

    mais bon en même temps, plus je "bricole" plus je m'embrouille. Je crois qu'il faudrait que je remette le pb à plat ...

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

Discussions similaires

  1. Construction d'une image pixel par pixel en multi-threads
    Par garheb dans le forum Débuter avec Java
    Réponses: 28
    Dernier message: 23/06/2013, 03h34
  2. [Multi-Thread] Mettre un msg d'attente lors d'un traitement long
    Par pepito62 dans le forum Composants VCL
    Réponses: 3
    Dernier message: 29/03/2013, 20h43
  3. Multi-threading barre de traitement
    Par kmtaz dans le forum Windows Forms
    Réponses: 7
    Dernier message: 15/05/2009, 08h38
  4. Tri multi-threadé
    Par Tifauv' dans le forum C
    Réponses: 8
    Dernier message: 28/06/2007, 09h00
  5. [Kylix] exception qtinft.dll et multi-threading
    Par leclaudio25 dans le forum EDI
    Réponses: 3
    Dernier message: 27/03/2003, 18h09

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