36 votes

C# pool de threads limitant les threads

Bon... J'ai fait une recherche approfondie sur le site et j'ai lu de nombreux messages sur ce sujet. J'ai trouvé cette question : Code pour un pool de threads simple en C# particulièrement utile.

Cependant, comme cela semble toujours le cas, ce dont j'ai besoin varie légèrement.

J'ai examiné l'exemple MSDN et l'ai quelque peu adapté à mes besoins. L'exemple auquel je me réfère est ici : http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80,imprimante).aspx

Mon problème est le suivant. J'ai un ensemble de code assez simple qui charge une page web via la page d'accueil. HttpWebRequest y WebResponse et lit les résultats via un Stream . Je lance cette méthode dans un fil de discussion car elle devra être exécutée plusieurs fois. La méthode elle-même est assez courte, mais le nombre de fois qu'elle doit être exécutée (avec des données variées à chaque fois) varie. Il peut aller de 1 à 200.

Tout ce que j'ai lu semble indiquer que ThreadPool La classe est le principal candidat. C'est là que les choses se compliquent. Je pourrais avoir besoin de déclencher cette chose disons 100 fois, mais je ne peux avoir que 3 threads au maximum en fonctionnement (pour cette tâche particulière).

J'ai essayé de régler le MaxThreads sur le ThreadPool via :

ThreadPool.SetMaxThreads(3, 3);

Je ne suis pas entièrement convaincu que cette approche fonctionne. De plus, je ne veux pas perturber les autres sites web ou programmes fonctionnant sur le système sur lequel il sera exécuté. Donc, en limitant le nombre de threads sur le serveur de l ThreadPool Comment puis-je être certain que cela concerne uniquement mon code et mes fils ?

L'exemple MSDN utilise l'approche du lecteur d'événements et appelle WaitHandle.WaitAll(doneEvents); ce qui est la façon dont je fais ça.

Le cœur de ma question est donc le suivant : comment garantir ou spécifier un nombre maximum de threads pouvant être exécutés pour son code, tout en laissant le code continuer à exécuter d'autres threads au fur et à mesure que les précédents se terminent jusqu'à un point arbitraire ? Est-ce que je m'y prends de la bonne façon ?

Sincèrement,

Jason


Ok, j'ai ajouté une approche de sémaphore et j'ai complètement supprimé la ThreadPool code. Cela semble assez simple. J'ai eu mes informations de : http://www.albahari.com/threading/part2.aspx

C'est cet exemple qui m'a montré comment faire :

[le texte ci-dessous est un copier/coller du site].

A Semaphore avec une capacité de un est similaire à un Mutex o lock sauf que le Semaphore n'a pas de "propriétaire" - il est agnostique. N'importe quel thread peut appeler Release sur un Semaphore tandis qu'avec Mutex y lock Si la ressource n'est pas disponible, seul le thread qui l'a obtenue peut la libérer.

Dans l'exemple suivant, dix threads exécutent une boucle avec une valeur de Sleep déclaration au milieu. A Semaphore s'assure que pas plus de trois threads peuvent exécuter cette Sleep La déclaration est faite immédiatement :

class SemaphoreTest
{
    static Semaphore s = new Semaphore(3, 3);  // Available=3; Capacity=3

    static void Main()
    {
        for (int i = 0; i < 10; i++)
            new Thread(Go).Start();
    }

    static void Go()
    {
        while (true)
        {
            s.WaitOne();

            Thread.Sleep(100);   // Only 3 threads can get here at once

            s.Release();
        }
    }
}

30voto

Michael Haren Points 42641

Remarque : si vous limitez ce nombre à "3" simplement pour ne pas surcharger la machine qui exécute votre application, je m'assurerais d'abord que c'est un problème. Le threadpool est censé gérer cela pour vous. D'un autre côté, si vous ne voulez pas surcharger une autre ressource, alors lisez la suite !


Vous ne pouvez pas gérer la taille du pool de threads (ni vraiment quoi que ce soit à ce sujet).

Dans ce cas, j'utiliserais un sémaphore pour gérer l'accès à votre ressource. Dans votre cas, votre ressource est en train d'exécuter le scrape web, ou de calculer un rapport, etc.

Pour ce faire, dans votre classe statique, créez un objet sémaphore :

System.Threading.Semaphore S = new System.Threading.Semaphore(3, 3);

Ensuite, dans chaque fil, vous faites ceci :

System.Threading.Semaphore S = new System.Threading.Semaphore(3, 3);

try
{
    // wait your turn (decrement)
    S.WaitOne();
    // do your thing
}

finally {
    // release so others can go (increment)
    S.Release();
}

Chaque thread bloquera sur le S.WaitOne() jusqu'à ce qu'il reçoive le signal pour continuer. Une fois que S a été décrémenté 3 fois, tous les threads se bloqueront jusqu'à ce que l'un d'entre eux incrémente le compteur.

Cette solution n'est pas parfaite.


Si vous voulez quelque chose de plus propre et de plus efficace, je vous recommande d'opter pour une approche de type BlockingQueue, dans laquelle vous mettez en file d'attente le travail à effectuer dans un objet BlockingQueueue global.

Pendant ce temps, vous avez trois threads (que vous avez créés - pas dans le pool de threads), qui sortent du travail de la file d'attente pour l'exécuter. Ce n'est pas très difficile à mettre en place et c'est très rapide et simple.

Exemples :

0voto

jalf Points 142628

C'est une classe statique comme une autre, ce qui signifie que tout ce que vous faites avec elle affecte tous les autres threads du processus en cours. Elle n'affecte pas les autres processus.

Je considère cependant que c'est l'un des plus gros défauts de conception de .NET. Qui a eu la brillante idée de faire du pool de threads statique ? Comme le montre votre exemple, nous souhaitons souvent disposer d'un pool de threads dédié à notre sans qu'elle n'interfère avec des tâches non liées ailleurs dans le système.

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