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 :

Comment limiter le nombre de Task exécutées en même temps ?


Sujet :

C#

  1. #1
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut Comment limiter le nombre de Task exécutées en même temps ?
    Bonjour,

    j'essaie de créer une sorte de ThreadPool avec des Tasks.
    J'ai une liste de tâches à effectuer représentées dans mon exemple ci-dessous par des classes WorkItem.
    Certaines sont dépendantes d'autres, c'est à dire, qu'elles ne doivent être lancées que lorsque celles dont elle dépend sont terminées (cf la propriété Precedents).

    J'ai donc créé des tâches qui sont lancées de suite et d'autres via Task.Factory.ContinueWhenAll.

    Mon soucis est qu'avec ce code, je ne peux pas limiter le nombre de Tasks lancées en même temps, il faudrait pouvoir le limiter car si j'ai trop de tâches en parallèle, j'ai les performances qui chutent drastiquement.

    J'ai tenté d'utiliser du PLinq et faire du travail du type .AsParallel().ForAll(() => ...) mais ça ne répond pas au besoin car il faut hiérarchiser les WorkItem via un rang et certains WorkItem ne se lancent pas alors que ces tâches précédentes sont terminées (je peux poster un code pour donner un exemple de cette solution et expliquer plus précisément ça ne fonctionne pas si cela s'avère nécessaire).

    Je n'arrive pas à trouver de ressource sur le net, alors je me permets de vous demander votre avis.

    Merci par avance pour votre aide.

    Voici un exemple de code :
    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
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
     
    namespace PoolThread
    {
        class Program
        {
            static void Main(string[] args)
            {
                var travaux = new List<WorkItem>();
     
                for (int i = 0; i < 10; i++)
                    travaux.Add(new WorkItem(i * 1000, true));
     
                for (int i = 0; i < 10; i++)
                    travaux.Add(new WorkItem(i * 1000, true, travaux.ToArray()));
     
                var taches = new List<Task>();
     
                foreach (var travail in travaux)
                {
                    if (travail.Precedents.Count == 0)
                        travail.Tache = new Task(() => travail.Work(), TaskCreationOptions.LongRunning);
                    else
                        travail.Tache = Task.Factory.ContinueWhenAll(travail.Precedents.Select(t => t.Tache).ToArray(), tasks => travail.Work(), TaskContinuationOptions.LongRunning);
     
                    taches.Add(travail.Tache);
                }
     
                try
                {
                    foreach (var travail in travaux)
                        if (travail.Precedents.Count == 0)
                            travail.Tache.Start();
     
                    Task.WaitAll(taches.ToArray());
     
                    Console.WriteLine("Fini");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
     
                Console.ReadLine();
            }      
        }
     
        public class WorkItem
        {
            private static int _Increment = 0;
     
            private readonly int _No;
            private readonly int _Duree;
            private readonly bool _IsSuccess;
     
            public WorkItem(int duree, bool isSuccess, params WorkItem[] precedents)
            {
                _No = _Increment++;
                _Duree = duree;
                _IsSuccess = isSuccess;
                Precedents = new List<WorkItem>(precedents);
            }
     
            public bool Work()
            {
                Console.WriteLine($"Début {_No}");
                Thread.Sleep(_Duree);
                Console.WriteLine($"Fin {_No}");
                return _IsSuccess;
            }
     
            public List<WorkItem> Precedents { get; }
     
            public Task Tache { get; set; }
        }
    }

  2. #2
    Membre confirmé Avatar de joKED
    Profil pro
    Imposteur en chef
    Inscrit en
    Février 2006
    Messages
    337
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Imposteur en chef

    Informations forums :
    Inscription : Février 2006
    Messages : 337
    Points : 458
    Points
    458
    Par défaut
    Salut,

    Jette un oeil ici : Parallel ForEach. Et notamment le second paramètre (ParallelOptions parallelOptions).
    Dans ces options, tu peux définir la propriété MaxDegreeOfParallelism qui définit le nombre max de taches effectuées en parallèle.
    Tant va la cruche à l'eau qu'à la fin y'a plus d'eau.

  3. #3
    Expert éminent sénior

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Charente Maritime (Poitou Charente)

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

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 758
    Points : 10 541
    Points
    10 541
    Billets dans le blog
    21
    Par défaut
    Bonjour,

    Tu peux regarder du côté de ThreadPool.SetMaxThreads qui devrait répondre à ton soucis.
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  4. #4
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut
    Bonjour,

    Citation Envoyé par joKED Voir le message
    Salut,

    Jette un oeil ici : Parallel ForEach. Et notamment le second paramètre (ParallelOptions parallelOptions).
    Dans ces options, tu peux définir la propriété MaxDegreeOfParallelism qui définit le nombre max de taches effectuées en parallèle.
    J'ai essayé de faire du Parallel.ForEach(), ça fonctionne bien pour les tâches qui sont lancées à la main, mais ça ne répond pas au besoin des tâches qui sont lancées automatiquement via ContinueWhenAll qui peuvent être très nombreuses en parallèle.

    Citation Envoyé par dorinf Voir le message
    Bonjour,

    Tu peux regarder du côté de ThreadPool.SetMaxThreads qui devrait répondre à ton soucis.
    Le problème est que l'utilisation d'un ThreadPool est contraignant, il n'y a pas de gestion d'exception, on ne peut pas récupérer la valeur de retour de la tâche et on ne peut pas l'annuler non plus.
    De plus, en utilisant le ThreadPool, on ne peut pas les ordonnancer.

  5. #5
    Expert éminent sénior

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Charente Maritime (Poitou Charente)

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

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 758
    Points : 10 541
    Points
    10 541
    Billets dans le blog
    21
    Par défaut
    Citation Envoyé par WebPac Voir le message
    Le problème est que l'utilisation d'un ThreadPool est contraignant, il n'y a pas de gestion d'exception, on ne peut pas récupérer la valeur de retour de la tâche et on ne peut pas l'annuler non plus
    Tu te trompes. Je t'invite à lire la série d'article que je suis en train d'écrire. Le deuxième est d'ailleurs paru ce matin même ! (pour accéder aux articles : http://fdorin.developpez.com/). Mais il est tout à fait possible de gérer les exceptions et de récupérer la valeur de retour en passant par les Task, ainsi que de les annuler (cf. les jetons d'annulation), car il faut voir les Task comme une surcouche basée sur l'utilisation du pool de threads.

    De plus, en utilisant le ThreadPool, on ne peut pas les ordonnancer.
    Ca, malheureusement, c'est une vérité. C'est une limitation de l'utilisation du pool de threads. Même les Tasks ne viennent pas combler ce manque.
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  6. #6
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut
    Salut,

    j'attendais avec impatience la seconde partie.
    Je l'ai lue et maintenant j'attends avec impatience la troisième et quatrième partie.

    Finalement, j'ai trouvé une solution en le gérant à la main.
    Toutes les tâches sont créées avec des new Task(), pas par des Task.Factory.ContinueWhenAll().
    Je mets des .Continue() sur chaque Task pour en lancer une autre par la suite à la main.

    Je pense que c'est la meilleure façon vu mon besoin.

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

Discussions similaires

  1. Comment limiter le nombre maximal de caractères d'un textarea ?
    Par hanafimohammed dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 17/05/2007, 21h03
  2. Comment limiter le nombre de sessions d'un utilisateur?
    Par nmathon dans le forum Sécurité
    Réponses: 19
    Dernier message: 28/03/2007, 11h26
  3. Réponses: 7
    Dernier message: 13/01/2007, 16h53
  4. [CR 9.0]Comment limiter le nombre d'enregistrements sur une page
    Par popol666 dans le forum SAP Crystal Reports
    Réponses: 2
    Dernier message: 06/11/2006, 15h27
  5. Comment limiter le nombre apres la virgule?
    Par pierrot10 dans le forum Langage
    Réponses: 2
    Dernier message: 25/10/2006, 22h12

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