Ограничение потоков пула потоков C # - PullRequest
36 голосов
/ 14 января 2009

Хорошо ... Я дал сайту честный поиск и прочитал много постов на эту тему. Я нашел этот вопрос: Код для простого пула потоков в C # особенно полезен.

Однако, как всегда кажется, то, что мне нужно, немного меняется.

Я просмотрел пример MSDN и немного адаптировал его к своим потребностям. Вот пример, на который я ссылаюсь: http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80,printer).aspx

Моя проблема заключается в следующем. У меня есть довольно простой набор кода, который загружает веб-страницу с помощью классов HttpWebRequest и WebResponse и считывает результаты с помощью Stream. Я запускаю этот метод в потоке, так как его нужно будет выполнять много раз. Сам метод довольно короткий, но количество его срабатываний (с разными данными каждый раз) варьируется. Может быть от 1 до 200.

Все, что я прочитал, указывает на то, что класс ThreadPool является основным кандидатом. Вот что становится сложнее. Мне может понадобиться запустить эту вещь, скажем, 100 раз, но у меня может быть не более 3 потоков (для этой конкретной задачи).

Я пытался установить MaxThreads на ThreadPool с помощью:

ThreadPool.SetMaxThreads(3, 3);

Я не совсем уверен, что этот подход работает. Кроме того, я не хочу блокировать другие веб-сайты или программы, работающие в системе, на которой он будет работать. Итак, ограничивая количество потоков в ThreadPool, могу ли я быть уверен, что это относится только к моему коду и моим потокам?

В примере MSDN используется подход к управлению событиями и вызывается WaitHandle.WaitAll(doneEvents);, как я это делаю.

Итак, суть моего вопроса в том, как обеспечить или указать максимальное количество потоков, которые могут быть запущены для их кода, но при этом заставить код продолжать работать больше потоков, пока предыдущие заканчивают работу до некоторой произвольной точки? Я решаю это правильно?

С уважением,

Jason


Хорошо, я добавил семафорный подход и полностью удалил код ThreadPool. Это кажется достаточно простым. Я получил информацию от: http://www.albahari.com/threading/part2.aspx

Именно этот пример показал мне, как:

[текст ниже - это копия / вставка с сайта]

A Semaphore с емкостью один аналогичен Mutex или lock, за исключением того, что Semaphore не имеет "владельца" - он не зависит от потоков. Любой поток может вызвать Release для Semaphore, тогда как с Mutex и lock только поток, получивший ресурс, может освободить его.

В следующем примере десять потоков выполняют цикл с оператором Sleep в середине. Semaphore гарантирует, что не более трех потоков могут выполнить этот оператор Sleep одновременно:

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();
        }
    }
}

Ответы [ 2 ]

30 голосов
/ 15 января 2009

Примечание: если вы ограничите это значение «3» только для того, чтобы не перегружать машину, на которой запущено ваше приложение, я бы сначала удостоверился, что это проблема. Предполагается, что поток потоков справится с этим за вас. С другой стороны, если вы не хотите перегружать какой-то другой ресурс, тогда читайте дальше!


Вы не можете управлять размером пула потоков (или вообще ничего о нем).

В этом случае я бы использовал семафор для управления доступом к вашему ресурсу. В вашем случае ваш ресурс выполняет веб-очистку или вычисляет какой-либо отчет и т. Д.

Для этого в вашем статическом классе создайте объект семафора:

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

Затем в каждой теме вы делаете это:

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();
}

Каждый поток будет блокироваться в S.WaitOne (), пока ему не будет дан сигнал для продолжения. Как только S уменьшится в 3 раза, все потоки будут блокироваться, пока один из них не увеличит счетчик.

Это решение не идеально.


Если вам нужно что-то более чистое и более эффективное, я бы порекомендовал использовать подход BlockingQueue, в котором вы ставите нужную работу в глобальный объект очереди блокировки.

Между тем, у вас есть три потока (которые вы создали - не в пуле потоков), выталкивающих работу из очереди для выполнения. Это не так сложно настроить и очень быстро и просто.

Примеры:

0 голосов
/ 15 января 2009

Это статический класс, как и любой другой, что означает, что все, что вы с ним делаете, влияет на все остальные потоки в текущем процессе. Это не влияет на другие процессы.

Однако я считаю это одним из самых больших недостатков дизайна в .NET. Кому пришла в голову блестящая идея сделать пул потоков статическим ? Как показывает ваш пример, нам часто требуется пул потоков, выделенный для нашей задачи, чтобы она не мешала другим задачам в других частях системы.

...