Когда мне не следует использовать ThreadPool в .Net?

Когда мне не следует использовать ThreadPool в .Net?

Похоже, что лучший вариант - использовать ThreadPool, и в таком случае, почему это не единственный вариант?

Что вы думаете об этом?

Ответов (9)

Решение

Единственная причина, по которой я не стал бы использовать ThreadPool для дешевой многопоточности, является то, что мне нужно…

  1. взаимодействовать с запущенным методом (например, чтобы убить его)
  2. запустить код в потоке STA (это случилось со мной)
  3. сохранить поток после того, как мое приложение умерло ( ThreadPoolпотоки являются фоновыми потоками)
  4. на случай, если мне нужно изменить приоритет потока. Мы не можем изменить приоритет потоков в ThreadPool, который по умолчанию является нормальным.

PS: Статья MSDN «Управляемый пул потоков» содержит раздел под названием «Когда не использовать потоки пула потоков с очень похожим, но немного более полным списком возможных причин неиспользования пула потоков.

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

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

У MSDN есть список причин здесь:

http://msdn.microsoft.com/en-us/library/0ka9477y.aspx

Существует несколько сценариев, в которых целесообразно создавать собственные потоки и управлять ими вместо использования потоков пула потоков:

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

Потоки Threadpool подходят для задач, отвечающих обоим следующим критериям:

  1. Задаче не придется тратить много времени на ожидание, чтобы что-то произошло.
  2. Все, что ожидает завершения задачи, скорее всего, будет ждать завершения многих задач, поэтому его приоритет планирования не может сильно влиять на ситуацию.

Использование потока threadpool вместо создания нового позволит сэкономить значительное, но ограниченное количество времени. Если это время значительно по сравнению со временем, которое потребуется для выполнения задачи, задача пула потоков, вероятно, подходит. Однако чем больше времени требуется для выполнения задачи, тем меньше польза от использования пула потоков и тем выше вероятность того, что задача снижает эффективность пула потоков.

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

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

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

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

@ Эрик

@Derek, я не совсем согласен со сценарием, который вы используете в качестве примера. Если вы точно не знаете, что работает на вашем компьютере и сколько всего потоков, дескрипторов, процессорного времени, оперативной памяти и т. Д., Которые ваше приложение будет использовать при определенной нагрузке, у вас проблемы.

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

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

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

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

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

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

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

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

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

@ Эрик, мне придется согласиться с Дином. Нитки дорогие. Вы не можете предполагать, что ваша программа работает только одна. Когда все жадны до ресурсов, проблема множится.

Я предпочитаю создавать свои темы вручную и контролировать их сам. Это делает код очень простым для понимания.

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

Thread t = new Thread(new ThreadStart(DoSomething));  
t.Start();  
t.Join();  

Я надеюсь, что у вас обычно будет дополнительный код между Start() и Join() . В противном случае дополнительный поток бесполезен, и вы тратите ресурсы без причины.

Люди слишком боятся ресурсов, используемых потоками. Я никогда не видел, чтобы создание и запуск потока занимало больше миллисекунды. Нет жесткого ограничения на количество создаваемых потоков. Использование оперативной памяти минимально. Когда у вас есть несколько сотен потоков, процессор становится проблемой из-за переключений контекста, поэтому на этом этапе вы можете захотеть поиграть со своим дизайном.

На современном оборудовании миллисекунда - это долгий срок. Это 3 миллиона циклов на машине с частотой 3 ГГц. И снова вы не единственный, кто создает темы. Ваши потоки конкурируют за ЦП вместе с потоками любой другой программы. Если вы используете не слишком много потоков, как и другая программа, то вместе вы использовали слишком много потоков.

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

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

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

Разумеется, два предостережения:

  1. Вы можете изменить максимальное количество потоков в пуле потоков в коде во время выполнения, поэтому ничто не мешает вам проверять текущее и максимальное число и при необходимости увеличивать максимальное.
  2. Создание новой нити связано со своим собственным штрафом времени - стоит ли вам принимать удар, зависит от ваших обстоятельств.

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

Ах, аргумент от авторитета - но всегда остерегайтесь людей, которые могут быть в команде ядра Windows.

Никто из нас не спорил с тем фактом, что если у вас есть какие-то особые требования, то .NET ThreadPool может быть неправильным. Мы возражаем против упрощения затрат машины на создание потока.

Существенные затраты на создание потока в первую очередь являются смыслом существования ThreadPool. Я не хочу, чтобы мои машины были заполнены кодом, написанным людьми, которые были дезинформированы о расходах на создание потока, и, например, не знают, что это вызывает вызов метода в каждой отдельной DLL, которая является присоединены к процессу (некоторые из которых будут созданы третьими сторонами), и который вполне может увеличить загрузку кода, который вообще не должен находиться в ОЗУ и почти наверняка не должен находиться в L1.

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