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 :

Récursivité et exécution d'un programme externe en parallèle (ExecutorService, ProcessBuilder)


Sujet :

Java

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 212
    Points : 146
    Points
    146
    Par défaut Récursivité et exécution d'un programme externe en parallèle (ExecutorService, ProcessBuilder)
    Bonjour,

    1) J'ai un exécutable externe à JAVA qui prend en entrée un fichier et m'en ressort un autre après traitement

    2) J'ai besoins de faire varier des valeurs dans le fichier d'entrée et de lire le fichier de résultat pour trouver les meilleurs valeurs.

    3) Les valeurs en entrée sont généré par une fonction récursive qui incrémente chaque paramètre pour obtenir toute les combinaisons possible.

    4) Lorsque j’exécute le programme externe dans la méthode récursive cela fonctionne très bien mais je suis obliger de laisser tourner toute une nuit pour obtenir des valeurs vu que la consommation CPU n’excède pas les 10%

    5) J'essais maintenant de lancer plusieurs programme en parallèle en utilisant ExecutorService pour gérer le nombre et le programme externe est exécuté via un ProcessBuilder

    666) C'est là que ça ce gâte.
    Dans une simple boucle FOR j'ai bien le nombre d’exécutable défini par l'ExecutorService lancé en même temps mais lorsque je place l’exécution dans ma fonction récursive je n'ai aucune variation des données. En fait si, j'ai une variation au tout début mais après plus rien.



    L'utilisation du ExecutorService

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ExecutorService exec = Executors.newFixedThreadPool(8);
    La génération des combinaisons avec Nom, borne basse, borne haute et incrément:
    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
     
        public static void combinaison() {
            List<Param> listeParam = Arrays.asList(
                    new Param("PARAM_ID", 2, 15, 1),
                    new Param("PARAM_RA", 0, 25, 5),
                    new Param("PARAM_RB", 0, 100, 10),
                    new Param("PARAM_RC", 40, 500, 20),
                    new Param("PARAM_RD", 20, 300, 20)
            );
     
            long nbrCombinaison = 1;
            for (Param param : listeParam) {
                long diff = (param.max - param.min);
                long inc = diff / param.inc + 1;
                nbrCombinaison = nbrCombinaison * inc;
            }
            System.out.println("Nombre de combinaison : "+nbrCombinaison);
            recur(listeParam, 0);
        }
     
        private static  void recur(List<Param> listeParam, int index) {
            Param param = listeParam.get(index);
            while (param.value <= param.max) {
                if (index < listeParam.size() - 1) {
                    recur(listeParam, index + 1);
                    param.value = param.value + param.inc;
                } else {
                    exec.execute(new ProcessRunnable(nbr,listeParam));
                    nbr++;
                    param.value = param.value + param.inc;
                }
            }
            param.value = param.min;
        }
    Comme vous pouvez le voir j'ai un Runnable qui est placé dans la fonction récursive qui va lire la combinaison courante. (L28)

    Le programme est exécuté comme ceci dans le Runnable :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    new ProcessBuilder(".exe" ,"-b", file).start().waitFor();
    Pouvez vous m'aider ?

    Si vous avez besoins d'autre bout de code ...

    Merci

  2. #2
    Membre habitué
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 212
    Points : 146
    Points
    146
    Par défaut
    Un exemple de combinaison si je remplace l’exécution du Runnable par cette fonction traitement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
        private static void traitement(List<Param> listeParam) {
            String combinaison = "";
            for (int i = 0; i < listeParam.size(); i++) {
                Param param = listeParam.get(i);
                combinaison = combinaison + param.value;
                if (i < listeParam.size() - 1) {
                    combinaison = combinaison + ";";
                }
     
            }
            System.out.println(combinaison);
        }

    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
    Nombre de combinaison : 332640
    2;0;0;40;20
    2;0;0;40;40
    2;0;0;40;60
    2;0;0;40;80
    2;0;0;40;100
    2;0;0;40;120
    2;0;0;40;140
    2;0;0;40;160
    2;0;0;40;180
    2;0;0;40;200
    2;0;0;40;220
    2;0;0;40;240
    2;0;0;40;260
    2;0;0;40;280
    2;0;0;40;300
    2;0;0;60;20
    2;0;0;60;40
    2;0;0;60;60
    2;0;0;60;80
    2;0;0;60;100
    2;0;0;60;120
    2;0;0;60;140
    2;0;0;60;160
    2;0;0;60;180
    2;0;0;60;200
    2;0;0;60;220
    2;0;0;60;240
    2;0;0;60;260
    2;0;0;60;280
    2;0;0;60;300
    2;0;0;80;20
    2;0;0;80;40
    2;0;0;80;60
    2;0;0;80;80
    2;0;0;80;100
    2;0;0;80;120
    2;0;0;80;140
    2;0;0;80;160
    2;0;0;80;180
    2;0;0;80;200

  3. #3
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Mais... Tu dis que tes données d'entrées viennent d'un fichier lu par ton programme externe (et les données de sorties dans un fichier écrit par ce programme.)

    Si tu fais ces traitements en parallèle... T'as pensé à utiliser des fichiers différents pour chaque traitement parallèle ? Il est où le code qui gère ça, c'est important.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 212
    Points : 146
    Points
    146
    Par défaut
    Bonjour,

    Oui je génère un fichier par combinaison avec un index dans le nom, donné au programme externe et détruit à la fin.

    Les fichiers sont bien généré et la simulation fonctionne mais les valeurs de combinaison ne sont pas incrémenté dans les fichiers.


    Vu que c'est juste un outil pour faciliter la vie sur un autre projet j'ai fais ça vite fait ce weekend donc c'est un brouillon

    Le code est bien entendu a améliorer

    Voilà le tout :


    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
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    package javaapplication2;
     
    import java.io.File;
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.List;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
     
    public class Param {
     
        public String name;
        public long value;
        public long min;
        public long max;
        public long inc;
     
        public static int nbr = 0;
        public static final String biasFile = ProcessRunnable.getContent(new File("C:/combinaison/schematicBIAS.net"));
        public static final String thdFile = ProcessRunnable.getContent(new File("C:/combinaison/schematicTHD.net"));
        public static ExecutorService exec = Executors.newFixedThreadPool(8);
     
     
        public Param(String name, int min, int max, int inc) {
            this.name = name;
            this.value = min;
            this.min = min;
            this.max = max;
            this.inc = inc;
        }
     
        private static void traitement(List<Param> listeParam) {
            String combinaison = "";
            for (int i = 0; i < listeParam.size(); i++) {
                Param param = listeParam.get(i);
                combinaison = combinaison + param.value;
                if (i < listeParam.size() - 1) {
                    combinaison = combinaison + ";";
                }
     
            }
            System.out.println(combinaison);
        }
     
     
        public static void combinaison()  {
            List<Param> listeParam = Arrays.asList(
                    new Param("PARAM_ID", 2, 15, 1),
                    new Param("PARAM_RA", 0, 25, 5),
                    new Param("PARAM_RB", 0, 100, 10),
                    new Param("PARAM_RC", 40, 500, 20),
                    new Param("PARAM_RD", 20, 300, 20)
            );
     
            long nbrCombinaison = 1;
            for (Param param : listeParam) {
                long diff = (param.max - param.min);
                long inc = diff / param.inc + 1;
                nbrCombinaison = nbrCombinaison * inc;
            }
            System.out.println("Nombre de combinaison : "+nbrCombinaison);
            recur(listeParam, 0);
        }
     
        private static  void recur(List<Param> listeParam, int index) {
            Param param = listeParam.get(index);
            while (param.value <= param.max) {
                if (index < listeParam.size() - 1) {
                    recur(listeParam, index + 1);
                    param.value = param.value + param.inc;
                } else {
                   // traitement(listeParam);
                   exec.execute(new ProcessRunnable(nbr,listeParam));
                    nbr++;
                    param.value = param.value + param.inc;
                }
            }
            param.value = param.min;
        }
    }

    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
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    package javaapplication2;
     
    import java.io.BufferedInputStream;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStreamWriter;
    import java.io.Writer;
    import java.nio.channels.FileChannel;
    import java.nio.charset.Charset;
    import java.util.List;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import static javaapplication2.Param.nbr;
     
    class ProcessRunnable implements Runnable{
     
        private int nbr;
        private List<Param> listeParam;
     
        ProcessRunnable(int nbr,List<Param> listeParam) {
            super();
            this.nbr=nbr;
            this.listeParam  =listeParam;
        }
     
        @Override
        public void run(){
            try {
                String biasFile = Param.biasFile;
                for (Param param : listeParam) {
                    String name =param.name;
                    String value = "";
                    if(param.value==0){
                        value = "0.001";
                    }else{
                        value = String.valueOf(param.value);
                    }
                    System.out.println(name + " / " +value);
                    biasFile=  biasFile.replaceAll(name,value);
                }
                File f = new File("C:/combinaison/sim/schematicBIAS"+this.nbr+".net");
                Charset charset = Charset.forName("UTF-8");
                Writer writer = new OutputStreamWriter(new FileOutputStream(f), charset);
                try {
                    writer.append(biasFile);
                } finally {
                    writer.close();
     
                }
                execCAD("C:/combinaison/sim/schematicBIAS"+this.nbr+".net");
                System.out.println(this.nbr+" / " + bias("C:/combinaison/sim/schematicBIAS"+this.nbr+".log"));
     
                f.delete();
                new File("C:/combinaison/sim/schematicBIAS"+this.nbr+".log").delete();
                new File("C:/combinaison/sim/schematicBIAS"+this.nbr+".raw").delete();
     
     
     
            } catch (IOException ex) {
                Logger.getLogger(ProcessRunnable.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InterruptedException ex) {
                Logger.getLogger(ProcessRunnable.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
     
        private static Float bias(String file) throws FileNotFoundException, IOException {
            BufferedReader buff = new BufferedReader(new FileReader(file));
            String line;
            while ((line = buff.readLine()) != null) {
                if (line.contains("i(v5)")) {
                    buff.close();
                    String valeur = line.split("-")[2];
                    return Float.valueOf(valeur);
                }
            }
            buff.close();
            return null;
        }
     
        private static void execCAD(String file) throws IOException, InterruptedException  {
            new ProcessBuilder("cad.exe" ,"-b", file).start().waitFor();
        }
     
        public static String getContent(File file) {
            String content = null;
            InputStream in = null;
            try {
                in = new BufferedInputStream(new FileInputStream(file));
                byte[] bytes = new byte[in.available()];
                in.read(bytes);
                content = new String(bytes);
     
            } catch (Exception e) {
                e.printStackTrace();
            }
            finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return content;
        }
    }

  5. #5
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    D'accord. Effectivement, les fichiers ont l'air d'être bien gérés pour le multithread.

    Ta List<Param> par contre... Tu la confies joyeusement aux threads de l'Executor, tout en continuant à la modifier dans ton thread principal.
    Ça va pas marcher -_-°. Il faut que tu construises une copie de la List, qui contient une copie de chaque Param, aux ProcessRunnable que tu construis.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Membre habitué
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 212
    Points : 146
    Points
    146
    Par défaut
    Merci beaucoup,

    Tu confirme ce que je me suis dis ce matin, ne plus passer la liste en paramètre mais directement les valeurs sous forme d'une MAP de String ou un autre objet plus simple que Param.

    Je vais essayer ça

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 212
    Points : 146
    Points
    146
    Par défaut
    Oui ça fonctionne en construisant un autre objet à passer en paramètre.

    Encore merci !

    Un exemple pour 500 exécutions :

    Sur un I5 M540 @ 2.5GHz ( 2 coeurs / 4 threads)

    1 thread : 112sec
    4 threads : 49sec
    12 threads : 26sec ce qui est pas mal même si j'aurais espéré moins, il faut que j'essais avec une autre machine

  8. #8
    Expert éminent sénior
    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
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,



    Désolé mais ce bout de code m'a fait hurler :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        private static void traitement(List<Param> listeParam) {
            String combinaison = "";
            for (int i = 0; i < listeParam.size(); i++) {
                Param param = listeParam.get(i);
                combinaison = combinaison + param.value;
                if (i < listeParam.size() - 1) {
                    combinaison = combinaison + ";";
                }
     
            }
            System.out.println(combinaison);
        }
    Il ne faut jamais utiliser l'opérateur + sur une String dans une boucle, car cela génère un grand nombre d'objet temporaire, ce qui va surcharger le GC inutilement.
    De plus le temps d'exécution sera exponentielle : il augmentera très vite avec le nombre d'itération.

    Chez moi ca donne à peu près ceci :
    • 2ms pour 100 éléments.
    • 8ms pour 1000 éléments.
    • 300ms pour 10 000 éléments.
    • 31 000ms pour 100 000 éléments.
    • ??? pour 1 000 000 éléments (je n'ai pas eu le courage d'attendre jusqu'à la fin).


    Pour construire une chaine de caractère il faut utiliser StringBuilder :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        private static void traitement(List<Param> listeParam) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < listeParam.size(); i++) {
                Param param = listeParam.get(i);
                sb.append(param.value);
                if (i < listeParam.size() - 1) {
                    sb.append(";");
                }
     
            }
            String combinaison = sb.toString();
            System.out.println(combinaison);
        }
    Ce qui donne des résultats bien plus respectable :
    • moins d'1ms pour 100 éléments.
    • moins d'1ms pour 1000 éléments.
    • moins d'1ms pour 10 000 éléments.
    • 16ms pour 100 000 éléments.
    • 50ms pour 1 000 000 éléments.






    Sinon je noterais comme dans beaucoup de code une gestion aléatoire des ressources.
    Pour bien faire il faut utiliser soit le try-with-ressource de Java 7, soit un try/finally par ressource, et ce dans tous les cas.


    Enfin la gestion des exceptions n'est pas très adéquate (on loggue l'erreur... mais on continue comme si de rien n'était).


    a++

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 212
    Points : 146
    Points
    146
    Par défaut
    Merci adiGuba, j'appliquerais tes recommandations dans la version suivante.

    Je me doute que tout ceci n'est pas bien mais ce n'est qu'un brouillon réalisé entre deux biberons demandés par mon fils de moins de deux mois

    La fonction traitement n'existe même plus, je ne l'ai faite que pour vérifier que ma génération de combinaisons fonctionnait correctement.

    Effectivement j'utilise habituellement StringBuilder, je gère correctement les exceptions, je log correctement avec log4J et je gère correctement mes ressources.

    Mon but premier était de vérifier si ce que je viens de faire était possible, je vais maintenant pouvoir réfléchir à une architecture, une structure de données pour la persistance et une interface.

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

Discussions similaires

  1. Exécution d'un programme externe
    Par DSGSLA dans le forum C++
    Réponses: 10
    Dernier message: 21/04/2010, 15h24
  2. Réponses: 7
    Dernier message: 03/12/2009, 16h22
  3. [Système] exécution d'un programme externe
    Par wonderyan dans le forum Langage
    Réponses: 2
    Dernier message: 17/09/2007, 12h40
  4. Réponses: 3
    Dernier message: 06/06/2007, 15h19
  5. exécution d'un programme externe
    Par didiss dans le forum API standards et tierces
    Réponses: 5
    Dernier message: 04/04/2007, 12h29

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