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

C# Discussion :

Parallélisme et progress


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mars 2007
    Messages : 249
    Par défaut Parallélisme et progress
    Salut,

    Soit une tâche statique "public static async Task<ObservableCollection<Pt>> ImportPointAsync(int srid, string mdbPath, IProgress<int> progress)"
    Cette tâche crée des points suite à la lecture de 2 tables.
    Comment fonctionne-t-elle actuellement ? Elle commence par charger les tables dans 2 DataTables puis, ligne par ligne, crée les points.
    La tâche fonctionne, mais vous comprenez que créer un par un plus de 60 000 point prend un peu de temps.
    Voici la partie de code qui m'intéresse (que je voudrais améliorer) :
    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
                ObservableCollection<Pt> points = new ObservableCollection<Pt>();
                int totalCount = dtPoints.Rows.Count;
                int processCount = await Task.Run<int>(() =>
                {
                    int count = 0;
                    foreach (DataRow drPoint in dtPoints.Rows)
                    {
                        if (drPoint != null)
                        {
                            DataRow[] drsPCodes = dtPCodes.Select("IdPoint = " + drPoint["IdPoint"]);
                            List<int> lstPCodes = new List<int>();
                            foreach (DataRow drPCode in drsPCodes)
                            {
                                int pcode = 0;
                                if (drPCode != null && int.TryParse(drPCode["PCode"].ToString(), out pcode))
                                    lstPCodes.Add(pcode);
                            }
                            Pt newPoint = new Pt(drPoint["nomPoint"].ToString(), (double)drPoint["PointX"], (double)drPoint["PointY"], lstPCodes, srid);
                            if (newPoint != null && !points.Contains(newPoint))
                                points.Add(newPoint);
                        }
                        if (progress != null)
                        {
                            progress.Report((count * 100 / totalCount));
                        }
                        count++;
                    }
     
     
                    return count;
                });
                if (points != null && points.Count > 0)
                    return points;
                return null;
    Que voudrais-je faire ? Paralléliser la création de points, mais c'est là que je coince depuis plusieurs jours et donc que je fais appel à vous.

    J'avais pensé à faire une liste des taches dont chaque tâche créerait 1000 points. Si déterminer les index de départ et de fin de lecture pour chaque tâche parallèle ne pose pas de problème (mais est-ce vraiment la meilleure solution ?), je voudrais que la tâche de base (ImportPointAsync) retourne la progression globale (en calculant le nombre de points créés en fonction du nombre de points que chaque tâche devrait retourner (comment faire cela et le gérer ?) et du total des lignes de la table dtpoints).

    Merci de vos z'avis z'avisés.

  2. #2
    Membre Expert
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2013
    Messages
    1 563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2013
    Messages : 1 563
    Par défaut
    Bonjour,

    Je ne m'y connais pas trop en parallélisme et tout, donc je prend le problème différemment : à quoi servent ces 60k points?

    Si c'est pour de l'affichage on peut considérer que l’entièreté des points n'est pas nécessaire tout de suite (on peu donc charger les points en arrière plant et rafraîchir régulièrement l'affichage)

  3. #3
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mars 2007
    Messages : 249
    Par défaut
    Malheureusement non. Ils ne seront pas affichés mais doivent tous être créés car ils forment des polygones qui doivent être vérifiés.
    Merci quand-même de l'intérêt que tu portes à mon problème.

  4. #4
    Expert confirmé

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Septembre 2006
    Messages
    3 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 580
    Par défaut
    Salut

    la solution de découper en plusieurs sous tache est une bonne idée

    pour la progression, regarde ce thread : http://stackoverflow.com/questions/1...rallel-foreach

    et sinon, tu peux surement améliorer en évitant quelques "erreurs"

    Si tu connais la taille de ta liste, tu peux dès la création de ta liste qui contiendra les données lui donner sa taille (genre new List(60000);
    tu gagneras du temps d'allocation mémoire pour commencer

    ensuite, tu fais souvent dans ton code : points.contains() ==> Ca coute cher aussi ça.. je peux comprendre que tu veuilles éviter d'éventuelle doublon, mais à ce moment
    là, peut-être qu'un dictionary et ou une table de hash te fera aussi gagner du temps

  5. #5
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mars 2007
    Messages : 249
    Par défaut
    Merci beaucoup theMonz31,
    J'avais trouvé "tout seul comme un grand" que les contains ralentissaient beaucoup.
    En les enlevant et en remplaçant le return par un Distinct de la list à retourner, je me suis rendu compte que je passais de 44 sec à ... 5.6 sec !!
    Par contre je ne savais pas que j'accélérerais en créant les listes avec leur taille finale (si connue bien entendu, mais dans ce cas ci c'est connu), et je ne connaissais pas du tout le Parallel.ForEach que j'avais donc "réinventé" (mais en moins bien évidemment). Grâce au Parallel.ForEach dans un await Task.Run, j'ai aussi pu gérer la progression.

    Pour ceux que cela intéressent, voici le code modifié suite aux précieux conseils de theMonz31 (Je vous fais grâce du début de la méthode qui charge la BDD dans des DataTables. Ce n'est pas l'objet de ma question de départ et j'imagine que tout le monde sait le faire)
    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
                if (dtPoints == null || dtPoints.Rows.Count == 0 || dtPCodes == null || dtPCodes.Rows.Count == 0)                return null;
                List<Pt> points = new List<Pt>(dtPoints.Rows.Count);
                int totalCount = dtPoints.Rows.Count, count = 1;
                Object obj = new Object();
                await Task.Run (() => 
                    Parallel.ForEach(dtPoints.AsEnumerable(), (drPoint) =>
                        {
                            if (drPoint != null)
                            {
                                DataRow[] drsPCodes = dtPCodes.Select("IdPoint = " + drPoint["IdPoint"]);
                                List<int> lstPCodes = new List<int>();
                                foreach (DataRow drPCode in drsPCodes)
                                {
                                    int pcode = 0;
                                    if (drPCode != null && int.TryParse(drPCode["PCode"].ToString(), out pcode))
                                        lstPCodes.Add(pcode);
                                }
                                Pt newPoint = new Pt(drPoint["nomPoint"].ToString(), (double)drPoint["PointX"], (double)drPoint["PointY"], lstPCodes, srid);
                                if (newPoint != null)
                                    points.Add(newPoint);
                            }
                            lock (obj)
                            {
                                if (progress != null)
                                {
                                    count++;
                                    progress.Report((count * 100 / totalCount));
                                }
                            }
                        })
                    );
                if (points != null && points.Count > 0)
                    return new ObservableCollection<Pt>(points.Distinct());
                return null;

  6. #6
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 941
    Par défaut
    Citation Envoyé par Jean-Marc68 Voir le message
    Par contre je ne savais pas que j'accélérerais en créant les listes avec leur taille finale (si connue bien entendu, mais dans ce cas ci c'est connu)
    Les conteneurs dynamiques comme les List gèrent souvent une taille (le nombre d'objets stockés) et une capacité (le nombre d'emplacements disponibles). Quand on veut ajouter un objet alors que la taille atteint déjà la capacité le conteneur, pour s'adapter, va réserver une nouvelle zone mémoire plus grande (généralement le double), recopier la première zone mémoire, la libérer, puis ajouter le nouvel item sur cette nouvelle zone. Si tu connais à l'avance le nombre d'objets à contenir tu peux demander à ta List de réserver directement la capacité dont elle a besoin et éviter cette effet de dépassement de seuil.

Discussions similaires

  1. Quelqu'un connait PROGRESS?
    Par sandrine dans le forum Autres SGBD
    Réponses: 23
    Dernier message: 07/05/2004, 11h29
  2. [web] Barre de Progression ASCII
    Par Red Bull dans le forum Web
    Réponses: 13
    Dernier message: 05/06/2003, 12h56
  3. PROGRESS- Obtenir le ROWNUM, ROWID, etc?!?
    Par nmathon dans le forum Requêtes
    Réponses: 4
    Dernier message: 27/05/2003, 14h05
  4. [Progress] Odbc
    Par NewB dans le forum Autres SGBD
    Réponses: 8
    Dernier message: 26/03/2003, 09h19

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