Подтвердить что ты не робот

Преимущество использования Thread.Start vs QueueUserWorkItem

В многопоточном .NET-программировании, каковы критерии принятия решения для использования ThreadPool.QueueUserWorkItem против запуска моего собственного потока через новые Thread() и Thread.Start()?

В серверном приложении (скажем, приложении ASP.NET или службе WCF) я думаю, что ThreadPool всегда существует и доступен. Что в клиентском приложении, например, в WinForms или WPF? Есть ли необходимость в раскрутке пула потоков? Если я просто хочу, чтобы 3 или 4 потока работали на короткий период при некоторых вычислениях, лучше ли QUWI или Thread.Start().

4b9b3361

Ответ 1

ThreadPool всегда присутствует, однако имеется конечное число потоков, распределенных для пула на основе количества процессоров. Для приложений ASP.NET обычно плохо использовать Threads, если вы действительно не начинаете процесс Async и знаете, что не будет большого количества запросов (помните, что в ThreadPool имеется конечное число потоков которые вы разделяете со всем, что работает в вашем AppDomain, и существует реальное ограничение на общее количество потоков, которые вы хотите создать, используя новый Thread()).

Для приложений WinForms рекомендуется использовать BackgroundWorker вместо использования Thread или ThreadPool. Он использует ThreadPool, однако он упрощает связь между потоками для многопоточного программиста.

Обновление

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

Из Hanselman.com - "Контрольный список: что НЕ делать в ASP.NET"

Ответ 2

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

Существует множество критериев, используемых для описания кода. Будет ли он использоваться в давно запущенном приложении или нет? Winforms приложение или нет? Это сервер или клиентское приложение? библиотеки или автономного exe? и т.д.

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

С другой стороны, если ваш код упакован как библиотека, которая может использоваться на сервере - в ASP.NET или, возможно, в приложении CLR для SQL или в службе WCF - тогда это действительно плохая идея создать потоки. Вам нужно использовать QUWI или какой-либо другой механизм, который использует встроенный пул потоков (например, BackgroundWorker). Если он будет использоваться в клиентских приложениях с другими библиотеками, снова требуется QUWI. Представьте себе, что каждая библиотека, желающая воспользоваться преимуществами многоядерных компьютеров, перекатила свои потоки. В приложениях, где используется больше, чем несколько библиотек, будет полный хаос. Rampant threads, все конкурирующие за одни и те же ресурсы. Нет центральной координации #threads vs # processor.

Хорошая гигиена требует, чтобы библиотека, потребляемая ею в клиентских приложениях или серверных приложениях, использует общий поток threadpool, а это означает QUWI.

Последняя вещь, чтобы понять это;

Управляемый поток представляет собой либо фоновый поток, либо поток переднего плана. Фоновые потоки идентичны потокам переднего плана с одним исключением: фоновый поток не поддерживает запущенную управляемую среду исполнения. Как только все потоки переднего плана были остановлены в управляемом процессе (где файл .exe является управляемой сборкой), система останавливает все фоновые потоки и завершает работу.

Нити, принадлежащие пулу управляемых потоков (то есть потоки, у которых свойство IsThreadPoolThread истинно) являются фоновыми потоками. Все потоки, входящие в управляемую среду исполнения из неуправляемого кода, помечены как фоновые потоки. Все потоки, созданные при создании и запуске нового объекта Thread, по умолчанию представляют собой потоки переднего плана.

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

с сайта

Ответ 4

Если ваши задачи коротки, вы, скорее всего, увидите гораздо лучшую производительность, планируя задачи в пуле потоков через QueueUserWorkItem или BeginInvoke, поскольку вы избегаете повторяющихся затрат на создание и уничтожение собственных потоков.

Пул потоков, очевидно, также платит за создание потоков, но он повторно использует потоки, поэтому вы не оплачиваете затраты на одну задачу.

Вы также можете взглянуть на Threading in С# (бесплатная электронная книга).

Ответ 5

Вот еще одно преимущество использования ThreadPool.QueueUserWorkItem.

У меня есть приложение winforms, которое имеет звуковой сигнал. Первоначально я реализовал это с помощью

            heartbeat = new Thread(HeartbeatDoWork);
        heartbeat.Start();

Что работает отлично в 98% случаев. Однако, когда приложение закрыто, оно иногда не "умирает", т.е. Процесс все еще отображается в диспетчере задач.

Чтобы быть кратким, heartbeat опубликовал событие, и он обрабатывал событие (CAB pub/sub), где он "застревал".

Исправить было легко, просто перейдите к использованию

            ThreadPool.QueueUserWorkItem(HeartbeatDoWork);

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

Ответ 6

Пул потоков всегда доступен в приложениях .NET, независимо от того, какой тип.

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

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

Ответ 7

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

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

Подобные дебаты, которые обычно происходят в сообществе С++ о строках, верят или нет. Должны ли мы каждый писать собственный собственный класс строк или использовать std::string? Ответ зависит от того, хотите ли вы научиться писать класс строк, или вы закончили с этим, и хотите продолжить разработку чего-то нового.

Ответ 8

Одним из преимуществ использования Thread.Start() является то, что вы можете намеренно прервать поток позже. В ThreadPool у вас нет средств контроля выполнения потока после его размещения в очереди.

Ответ 9

Большинство моих чтений согласны с Марселем, способность контролировать поток, если что-то идет (Abort...) - это то, что должно быть сильно рассмотрено, особенно если вы имеете дело со сторонними вызовами, над которыми вы не имеете контроля, и можете висеть.