Пул потоков C#, ограничивающий потоки

Хорошо ... Я провел тщательный поиск по сайту и прочитал много сообщений по этой теме. Я нашел этот вопрос: Код для простого пула потоков на 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);, как я это делаю.

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

Искренне,

Джейсон


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

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

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

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();
        }
    }
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
36
0
46 484
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

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

Пул потоков предназначен для использования в рамках всего процесса. Вам нужен диспетчер задач, который можно установить по запросу. Если вы посмотрите на ParallelLINQ и библиотеку параллельных задач от Microsoft (которая будет добавлена ​​в .NET 4), то увидите, что вы ищете.

Judah Gabriel Himango 15.01.2009 00:33

Это не значит, что это не недостаток дизайна. Им следовало разрешить создание его экземпляров по запросу с первого дня. Конечно, ничто не мешает им также предоставить статический экземпляр этого класса, если они хотят явно поддерживать «общепроцессные» задачи. Но я рад, что .NET4 наконец исправит это.

jalf 15.01.2009 04:16

Это имеет большой смысл, когда вы понимаете, что количество доступных процессоров / ядер также довольно статично. И они в любом случае используются всеми другими процессами, задачами и потоками. Так какой же смысл в том, чтобы два пула потоков в одном приложении конкурировали друг с другом за один и тот же набор ресурсов ЦП?

MSalters 07.09.2009 17:20

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

jalf 07.09.2009 17:43

Вы можете легко создать свой собственный пул потоков, если не хотите использовать статический.

Cheeso 04.11.2009 14:27

@Judah - я считаю, что параллельная библиотека по умолчанию использует ThreadPool под покровом, поэтому, если статический ThreadPool представляет собой проблему без библиотеки Parallel, это все равно будет проблемой с участием, параллельная библиотека.

Daniel Schilling 12.09.2011 20:09
Ответ принят как подходящий

Примечание: если вы ограничиваете это число до «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, при котором вы помещаете работу, которую хотите выполнить, в глобальный объект Blocking Queue.

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

Примеры:

Разве это не должно быть Semaphore (3,3), уменьшение WaitOne и приращение Release?

Bjarke Ebert 07.09.2009 14:56

@Bjarke Ebert: спасибо за исправление: я обновил ответ

Michael Haren 07.09.2009 17:14

Майкл, не могли бы вы подробнее рассказать о примере с семафором? Я впервые прочитал / услышал о них.

jason baisden 15.01.2009 00:30

Джейсон: Я определенно рекомендую второй подход (блокирующая очередь / производитель-потребитель) - это намного проще, IMO. Тем не менее, чтобы узнать больше о семафорах, прочтите это: msdn.microsoft.com/en-us/library/…

Michael Haren 15.01.2009 00:40

Другие вопросы по теме