43 votes

System.Threading.Tasks - Limiter le nombre de tâches concurrentes

Je viens de commencer à examiner la nouvelle bonté de "System.Threading.Tasks" dans .Net 4.0, et je voudrais savoir s'il existe un support intégré pour limiter le nombre de tâches simultanées qui s'exécutent en même temps, ou si cela doit être géré manuellement.

Par exemple, si j'ai besoin d'appeler une méthode de calcul 100 fois, y a-t-il un moyen de configurer 100 tâches, mais de n'en faire exécuter que 5 simultanément ? La réponse est peut-être de créer 5 tâches, d'appeler Task.WaitAny, et de créer une nouvelle tâche à la fin de chaque tâche précédente. Je veux juste m'assurer que je ne rate pas une astuce s'il existe une meilleure façon de procéder.

En fait, existe-t-il un moyen intégré de le faire ?

Dim taskArray() = {New Task(Function() DoComputation1()),
                   New Task(Function() DoComputation2()),
                   ...
                   New Task(Function() DoComputation100())}

Dim maxConcurrentThreads As Integer = 5
RunAllTasks(taskArray, maxConcurrentThreads)

Merci pour toute aide.

45voto

James Points 2551

Je sais que ce sujet date de presque un an, mais j'ai trouvé un moyen beaucoup plus facile d'y parvenir, alors j'ai pensé que je devais le partager :

Dim actionsArray() As Action = 
     new Action(){
         New Action(Sub() DoComputation1()),
         New Action(Sub() DoComputation2()),
         ...
         New Action(Sub() DoComputation100())
      }

System.Threading.Tasks.Parallel.Invoke(New Tasks.ParallelOptions() With {.MaxDegreeOfParallelism = 5}, actionsArray)

Voilà !

28voto

Arrow_Raider Points 151

Je sais que c'est un vieux fil de discussion, mais je voulais juste partager ma solution à ce problème : utiliser les sémaphores.

(Ceci est en C#)

private void RunAllActions(IEnumerable<Action> actions, int maxConcurrency)
{
    using(SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency))
    {
        foreach(Action action in actions)
        {
            Task.Factory.StartNew(() =>
            {
                concurrencySemaphore.Wait();
                try
                {
                    action();
                }
                finally
                {
                    concurrencySemaphore.Release();
                }
            });
        }
    }
}

7voto

persistent Points 133

Une solution pourrait être de jeter un coup d'œil au code préétabli de Microsoft aquí .

La description est la suivante : "Fournit un planificateur de tâches qui assure un niveau de concurrence maximal tout en fonctionnant au-dessus du ThreadPool.", et pour autant que j'aie pu le tester, il semble faire l'affaire, de la même manière que la propriété MaxDegreeOfParallelism dans ParallelOptions.

6voto

Nigrimmist Points 41

L'équivalent en C# de l'échantillon fourni par James

Action[] actionsArray = new Action[] {
new Action(() => DoComputation1()),
new Action(() => DoComputation2()),
    //...
new Action(() => DoComputation100())
  };

   System.Threading.Tasks.Parallel.Invoke(new Tasks.ParallelOptions {MaxDegreeOfParallelism =  5 }, actionsArray)

3voto

Rich Turner Points 4845

Réponse courte : Si ce que vous voulez, c'est limiter le nombre de tâches de travailleur afin qu'elles ne saturent pas votre service web, alors je pense que votre approche est bonne.

Réponse longue : Le nouveau moteur System.Threading.Tasks de .NET 4.0 fonctionne au-dessus du ThreadPool de .NET. Étant donné qu'il n'y a qu'un seul ThreadPool par processus et que le nombre de threads par défaut est de 250. Par conséquent, si vous fixez le nombre maximal de threads du ThreadPool à un nombre plus modeste, vous pourrez peut-être réduire le nombre de threads s'exécutant simultanément, et donc de tâches, à l'aide de la fonction ThreadPool.SetMaxThreads (...) API.

CEPENDANT, notez que vous n'êtes peut-être pas le seul à utiliser le ThreadPool, car de nombreuses autres classes que vous utilisez peuvent également mettre des éléments en file d'attente dans le ThreadPool. Par conséquent, il y a de fortes chances que vous finissiez par paralyser le reste de votre application en faisant cela. Notez également qu'étant donné que le ThreadPool utilise un algorithme pour optimiser son utilisation des cœurs sous-jacents d'une machine donnée, limiter le nombre de threads que le threadpool peut mettre en file d'attente à un nombre arbitrairement bas peut entraîner des problèmes de performance assez catastrophiques.

Encore une fois, si vous souhaitez exécuter un petit nombre de tâches/threads de travailleur pour exercer une certaine tâche, la meilleure approche consiste à ne créer qu'un petit nombre de tâches (plutôt que des centaines).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X