Это правильный случай для использования Threadpool? - PullRequest
2 голосов
/ 17 ноября 2009

Вот настройка: я пытаюсь создать относительно простое приложение Winforms, считывающее устройство, использующее библиотеку FeedDotNet . У меня вопрос об использовании пула потоков. Поскольку FeedDotNet выполняет синхронные HttpWebRequests, он блокирует поток GUI. Так что лучше всего было бы сделать синхронный вызов потока ThreadPool и, пока он работает, вызывать элементы управления, которые необходимо обновить в форме. Немного грубый код:

private void ThreadProc(object state)
{
 Interlocked.Increment(ref updatesPending);

    // check that main form isn't closed/closing so that we don't get an ObjectDisposedException exception
 if (this.IsDisposed || !this.IsHandleCreated) return;
 if (this.InvokeRequired)
  this.Invoke((MethodInvoker)delegate
  {
   if (!marqueeProgressBar.Visible)
    this.marqueeProgressBar.Visible = true;
  });

 ThreadAction t = state as ThreadAction;
 Feed feed = FeedReader.Read(t.XmlUri);

 Interlocked.Decrement(ref updatesPending);

 if (this.IsDisposed || !this.IsHandleCreated) return;
 if (this.InvokeRequired)
  this.Invoke((MethodInvoker)delegate { ProcessFeedResult(feed, t.Action, t.Node); });

 // finished everything, hide progress bar
 if (updatesPending == 0)
 {
  if (this.IsDisposed || !this.IsHandleCreated) return;
  if (this.InvokeRequired)
   this.Invoke((MethodInvoker)delegate { this.marqueeProgressBar.Visible = false; });
 }
}

this = основной экземпляр формы

updatesPending = volatile int в основной форме

ProcessFeedResult = метод, который выполняет некоторые операции с объектом Feed. Поскольку поток пула потоков не может вернуть результат, является ли это приемлемым способом обработки результата через основной поток?

Главное, что меня беспокоит, это то, как это масштабируется. Я пробовал ~ 250 запросов одновременно. Максимальное количество потоков, которые я видел, было около 53, и как только все потоки были завершены, до 21. Я помню, что в одном исключительном случае я играл с кодом, я видел, как он поднимается до 120. не так ли? Кроме того, учитывая Windows XP, я считаю, что при таком большом количестве соединений где-то возникнет узкое место. Я прав?

Что я могу сделать, чтобы обеспечить максимальную эффективность потоков / соединений?

Наличие всех этих вопросов также заставило меня задуматься, является ли это правильным случаем для использования Threadpool. MSDN и другие источники говорят, что его следует использовать для «непродолжительных» задач. Достаточно ли недолговечно 1-2 секунды, учитывая, что я на относительно быстром соединении? Что если пользователь подключен к сети 56K и один запрос может занять от 5 до 12 секунд и даже больше. Тогда пул потоков был бы эффективным решением?

Ответы [ 5 ]

2 голосов
/ 17 ноября 2009

Несколько баллов, и для объединения информации формируют несколько других ответов:

  • ваш ThreadProc не содержит обработку исключений. Вы должны добавить это или 1 ошибка ввода / вывода остановит ваш процесс.
  • Сэм Саффрон совершенно прав, что вам следует ограничить количество потоков. Вы можете использовать очередь (ThreadSafe), чтобы протолкнуть свои каналы в (WorkItems) и получить 1+ потоков, читающих из очереди в цикле.
  • BackgrounWorker может быть хорошей идеей, он предоставит вам необходимую обработку исключений и синхронизацию.
  • А BackgrounWorker использует ThreadPool, и это нормально
2 голосов
/ 17 ноября 2009

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

Идея состоит в том, чтобы задача запрыгнула в поток, быстро запустилась, завершилась и отскочила.

Класс BackgroundWorker обеспечивает простой способ выполнения задач в потоке пула потоков и предоставляет механизмы для отчета о ходе выполнения и обработки запросов на отмену.

В этой статье MSDN о компоненте BackgroundWorker загрузки файлов явно приведены в качестве примеров надлежащего использования этого класса. Мы надеемся, что это побудит вас использовать этот класс для выполнения необходимой работы.

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

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

2 голосов
/ 17 ноября 2009

Мое понимание ThreadPool заключается в том, что он предназначен для такого типа ситуаций. Я думаю, что определение недолговечное имеет такой порядок времени - возможно, даже до минут. «Долгоживущим» потоком будет тот, который был жив в течение всей жизни приложения.

Не забывайте, что Microsoft потратила бы немного на повышение эффективности ThreadPool. Как вы думаете, вы могли бы написать что-то более эффективное? Я знаю, что не мог.

2 голосов
/ 17 ноября 2009

ThreadPool, unchecked , вероятно, плохая идея.

Из коробки вы получаете 250 потоков в пуле потоков за процессор .

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

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

Хотя это можно организовать с помощью ThreadPool, лучше использовать выделенные потоки или использовать что-то вроде набора экземпляров класса BackgroundWorker.

1 голос
/ 17 ноября 2009

Возможно, вы захотите взглянуть на "BackgroundWorker" класс.

...