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 :

Programmation parallèle, Tasks et gestion des accès sur une liste.


Sujet :

C#

  1. #1
    Membre du Club Avatar de Parmifer
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2014
    Messages
    39
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2014
    Messages : 39
    Points : 51
    Points
    51
    Par défaut Programmation parallèle, Tasks et gestion des accès sur une liste.
    Bonjour.

    Dans ce topic, j'ai eu à gérer un petit problème en effectuant deux boucles espacées d'une minute. Mais voilà, l’exécution du programme est relativement longue.

    Afin de résoudre cela, on m'avait proposé d'utiliser deux Threads de façon à commencer la première boucle, laisser tourner ça une minute et pour finir, lancer la deuxième boucle.

    Je me suis un peu documenté et je me suis rendu compte qu'il existe maintenant des Tasks bien plus efficaces et facile à mettre en place (Parallel.ForEach par exemple). Cependant je ne sais pas comment faire en sorte que la deuxième boucle se lance au bout d'une minute.

    Enfin, je vais devoir accéder à une même collection (ArrayList) avec les deux boucles. L'une ajoutant des objets dedans, l'autre faisant un traitement sur chaque objet.

    Je n'ai pas vraiment encore fait de code mais on obtiendrait un truc du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    Parallel.ForEach(liste1, objet1 =>
    {
        //Traitement sur objet1
        //Création d'un objet2
        //Ajout de l'objet2 dans liste 2
    });
     
    //Au bout de 60000 ms, on lance une task
     
    Task maTache = Task.Factory.StartNew(uneMethode);
    uneMethode
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    foreach(Object objet2 in liste2)
    {
        //traitement sur objet2
    }
    Bon, y'a sans doute des fautes, des imprécisions et toussa, et pour cause : c'est encore très flou.

    Quelqu'un à une piste à me donner? Une fonction à me proposer? Des corrections à effectuer?

    Merci !
    Parmifèr

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while(cafe <= 0)
    {
        developper = false;
    }

  2. #2
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2014
    Messages : 9
    Points : 25
    Points
    25
    Par défaut
    peux tu expliquer concrètement ce que tu veux faire sans commencer par ce que tu as essayé de faire ?
    car moi je ne vois pas ce que tu veux faire et je n'ai pas envie de comprendre ce que tu as essayé de faire sans avoir cerné le problème à la base.

    A disposition

  3. #3
    Membre du Club Avatar de Parmifer
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2014
    Messages
    39
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2014
    Messages : 39
    Points : 51
    Points
    51
    Par défaut
    Bonjour.

    L'idée en gros c'est de copier des fichiers depuis un point A vers un point B puis d'affecter la date de dernier accès du fichier source au fichier copié. Or, comme vous le savez peut-être, il faut un moment avant de pouvoir faire un traitement sur un fichier copié (sinon il n'est pas pris en compte). La date est stockée dans un objet que j'ai créé (qui se base sur un FileInfo).

    La solution à ce problème ayant déjà été apportée, ce n'était pas très pertinent de s'attarder dessus.

    Est-ce plus clair?

    PS : J'ai presque résolu mon souci en fait, j'ai encore besoin de quelques (LONGS) tests sur quelques milliers de fichiers avant d'en être certain. En attendant, je reste à votre écoute.
    Parmifèr

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while(cafe <= 0)
    {
        developper = false;
    }

  4. #4
    Membre habitué

    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juillet 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur intégration

    Informations forums :
    Inscription : Juillet 2009
    Messages : 62
    Points : 157
    Points
    157
    Par défaut
    Citation Envoyé par Parmifer Voir le message
    Bonjour.
    Enfin, je vais devoir accéder à une même collection (ArrayList) avec les deux boucles.
    Concernant l’accès simultané de plusieurs threads à un même objet type collection, regarde les classes de collection thread-safe System.Collections.Concurrent

  5. #5
    Membre du Club Avatar de Parmifer
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2014
    Messages
    39
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2014
    Messages : 39
    Points : 51
    Points
    51
    Par défaut
    Effectivement, je pense pouvoir gagner du temps avec ce genre de collections en évitant les lock à foison.

    Merci pour la piste, c'est exactement le genre de choses que je recherchais.

    Du coup, j'ai ce code là pour le moment :

    Code archiver() : 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
    public void archiver()
    {
        //Debug
        Console.WriteLine("~~~~~~~~~ Archiver ~~~~~~~~~\n");
        if (mesFichiersH != null && mesFichiersH.Count != 0)
        {
            Task maTache = Task.Factory.StartNew(tacheCopie);
     
            Console.WriteLine("Sleep\n");
            Thread.Sleep(60000);
            Console.WriteLine("WakeUp\n");
     
            tacheDateAcces();
     
            Console.WriteLine("Nb fichier copiés : {0}\n", mesFichiersCopie.Count);
            Console.WriteLine("Nb dates changées : {0}\n", nbChangement);
        }
    }

    Code tacheCopie() : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    private void tacheCopie()
    {
        //Debug
        Console.WriteLine("~~~~~~~~~ ThreadCopie ~~~~~~~~~\n");
    
        //Log
        Log monLog = new Log("Archivage");
    
        foreach (FileInfoPerso monFichierH in mesFichiersH)
        {
            copieArchiver(monFichierH, monLog); //Ici on copie le fichier H et on créé un FileInfoPerso dans le concurrentBag mesFichiersCopie
        }
    }

    Code tacheDateAcces() : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    private void tacheDateAcces()
    {
        Console.WriteLine("~~~~~~~~~ ThreadAcces ~~~~~~~~~\n");
    
        for(int i = 0; i < mesFichiersCopie.Count; i++)
        {
            dateAccesArchiver(mesFichiersCopie.ElementAt(i)); //Ici on change la date d'accès des fichiers
        }
    
        estArchiveH = true; 
    }
    Parmifèr

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while(cafe <= 0)
    {
        developper = false;
    }

  6. #6
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    Attention avec les collections lock-free, ce n'est pas toujours plus efficace, surtout si la contention est forte. Avec plusieurs tentatives simultanées d'écriture ça peut même vite dégénérer (comme toujours avec les mécanismes de concurrence optimiste). Par contre ça simplifie l'écriture du code en évitant un verrouillage explicite. Et ici je ne pense pas que le risque de dégénérescence existe.

    Si j'ai bien compris tu as une file d'attente et tu te fiches de l'ordre dans lequel les éléments sont placés ? TU cherches simplement à pouvoir retirer des éléments en même temps que tu en ajoutes ? Et tes opérations ne sont pas à haute fréquence puisqu'elles interviennent après des modifications sur des fichiers, toujours lentes ? Et ton goulet d'étranglement n'est donc pas sur la collection ou même le CPU mais sur l'écriture des fichiers ?



    Voilà comment moi j'aurais fait :
    * Je commencerais par me demander si j'ai le moindre problème de performances. Car si ce n'est pas le cas j'écrirais simplement le plus joli, le plus lisible et le plus maintenable code possible, en ignorant tout ce qui va suivre.

    * Plutôt que d'utiliser Parallel.Foreach, j'aurais utilisé les fonctions asynchrones de Stream en dotnet 4.5 car elles exploitent des fonctions spécifiques du système d'exploitation dédiées aux opérations I/O asynchrones ("I/O completion ports") ce qui est à coup sûr le meilleur moyen d'obtenir les meilleures performances possibles en maximisant le nombre simultané d'écritures (que Windows réorganisera pour optimiser l'accès). Le ThreadPool utilisé par Parallel.ForEach se débrouillera typiquement moins bien sur ce genre de choses.

    * Comme toi j'essaierais de ne pas garder des pelletées de threads attendant 60s. Donc "deux boucles" comme tu disais.

    * Pour le reste je ne m'en ferais pas et je veillerais à garder mon code le plus simple possible en utilisant une bête ConcurrentQueue et le couple async/await.

  7. #7
    Membre du Club Avatar de Parmifer
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2014
    Messages
    39
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2014
    Messages : 39
    Points : 51
    Points
    51
    Par défaut
    Si j'ai bien compris tu as une file d'attente et tu te fiches de l'ordre dans lequel les éléments sont placés ?
    Non. Justement, je dois attendre que les fichiers soient copiés avant de pouvoir faire quoi que ce soit dessus.

    TU cherches simplement à pouvoir retirer des éléments en même temps que tu en ajoutes ?
    Toujours pas. En fait on fait juste un traitement sur les fichier de la liste, du haut vers le bas tout en ajoutant d'autres fichiers en bas.
    Dans l'idéal il faudrait que ce soit 1 fichier/1 fichier à partir d'une minute de traitement.

    Et tes opérations ne sont pas à haute fréquence puisqu'elles interviennent après des modifications sur des fichiers, toujours lentes ?
    La copie peut être assez lente car on génère le chemin avant (et il faut créer les répertoires de destination s'ils n'existent pas. De plus, si le fichier est un peu lourd, ça ajoute du temps. En gros on est entre 500 et 1500 ms par copie. Par contre la modif est plus rapide (300-500ms).

    Et ton goulet d'étranglement n'est donc pas sur la collection ou même le CPU mais sur l'écriture des fichiers ?
    C'est cela, je suis obligé d'attendre la copie + 60 sec (on peut mettre plus, on peut mettre moins mais je n'ai jamais eu de souci avec 60) avant de pouvoir faire le moindre traitement (à cause du système de fichier Windows).

    * Je commencerais par me demander si j'ai le moindre problème de performances. Car si ce n'est pas le cas j'écrirais simplement le plus joli, le plus lisible et le plus maintenable code possible, en ignorant tout ce qui va suivre.
    Effectivement, j'y avais pensé mais je n'ai toujours pas pu faire de test à échelle réelle. Toujours est-il que j'ai préféré commencer à chercher une solution tout de suite plutôt que de me retrouver coincé par le temps.

    * Plutôt que d'utiliser Parallel.Foreach, j'aurais utilisé les fonctions asynchrones de Stream en dotnet 4.5 car elles exploitent des fonctions spécifiques du système d'exploitation dédiées aux opérations I/O asynchrones ("I/O completion ports") ce qui est à coup sûr le meilleur moyen d'obtenir les meilleures performances possibles en maximisant le nombre simultané d'écritures (que Windows réorganisera pour optimiser l'accès). Le ThreadPool utilisé par Parallel.ForEach se débrouillera typiquement moins bien sur ce genre de choses.
    Oh? J'irai chercher de ce côté là alors, merci !

    * Pour le reste je ne m'en ferais pas et je veillerais à garder mon code le plus simple possible en utilisant une bête ConcurrentQueue et le couple async/await.
    J'ai finalement opté par un ConcurrentQueue après avoir relu la doc plus précisément. Par contre, je ne sais pas ce que c'est que le couple async/await. Jamais utilisé.

    Merci pour ta réponse !
    Parmifèr

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while(cafe <= 0)
    {
        developper = false;
    }

Discussions similaires

  1. gestion des accès sur PDA
    Par adilensa dans le forum Windows Mobile
    Réponses: 1
    Dernier message: 21/01/2011, 20h37
  2. gestion des accès sur PDA
    Par adilensa dans le forum Windows Mobile
    Réponses: 0
    Dernier message: 13/01/2011, 12h23
  3. gestion des accès dans une appli VB6
    Par bricew dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 16/04/2008, 08h49
  4. Gestion des Callbacks sur une scrolling Bar
    Par neptune2024 dans le forum Interfaces Graphiques
    Réponses: 1
    Dernier message: 22/11/2007, 09h31
  5. Gestion des erreurs sur une commande multiple
    Par domiq44 dans le forum Shell et commandes GNU
    Réponses: 5
    Dernier message: 05/10/2006, 15h03

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