Другие ответы здесь, похоже, не учитывают самый важный момент:
Если вы не пытаетесь распараллелить операцию, интенсивно использующую ЦП, чтобы ускорить ее выполнение на сайте с низкой нагрузкой, нет никакого смысла использовать рабочий поток вообще.
Это касается как бесплатных потоков, созданных new Thread(...)
, так и рабочих потоков ThreadPool
, отвечающих на QueueUserWorkItem
запросы.
Да, это правда, вы можете заморозить ThreadPool
процесс ASP.NET, поставив в очередь слишком много рабочих элементов. Это предотвратит обработку дальнейших запросов ASP.NET. Информация в статье верна в этом отношении; тот же пул потоков используется для QueueUserWorkItem
обслуживания запросов.
Но если вы действительно ставите в очередь достаточно рабочих элементов, чтобы вызвать голод, тогда вам следует истощить пул потоков! Если вы выполняете буквально сотни операций с интенсивным использованием ЦП одновременно, какой смысл иметь другой рабочий поток для обслуживания запроса ASP.NET, когда машина уже перегружена? Если вы столкнулись с такой ситуацией, вам нужно полностью переделать дизайн!
В большинстве случаев я вижу или слышу о том, что многопоточный код используется ненадлежащим образом в ASP.NET, это не для постановки в очередь работы, интенсивно использующей процессор. Это для постановки в очередь работы, связанной с вводом-выводом. И если вы хотите выполнять операции ввода-вывода, вам следует использовать поток ввода-вывода (порт завершения ввода-вывода).
В частности, вы должны использовать асинхронные обратные вызовы, поддерживаемые любым классом библиотеки, который вы используете. Эти методы всегда очень четко обозначены; они начинаются со слов Begin
и End
. Как и в Stream.BeginRead
, Socket.BeginConnect
, WebRequest.BeginGetResponse
, и так далее.
Эти методы действительно используют ThreadPool
, но они используют IOCP, которые не мешают запросам ASP.NET. Это особый вид облегченного потока, который может быть «разбужен» сигналом прерывания от системы ввода-вывода. А в приложении ASP.NET у вас обычно есть один поток ввода-вывода для каждого рабочего потока, поэтому для каждого отдельного запроса может быть поставлена в очередь одна асинхронная операция. Это буквально сотни асинхронных операций без значительного снижения производительности (при условии, что подсистема ввода-вывода может не отставать). Это намного больше, чем вам когда-либо понадобится.
Просто имейте в виду, что асинхронные делегаты не работают таким образом - они в конечном итоге будут использовать рабочий поток, как и ThreadPool.QueueUserWorkItem
. На это способны только встроенные асинхронные методы классов библиотеки .NET Framework. Вы можете сделать это сами, но это сложно и немного опасно и, вероятно, выходит за рамки этого обсуждения.
На мой взгляд, лучший ответ на этот вопрос - не использовать ThreadPool
или фоновый Thread
экземпляр в ASP.NET . Это совсем не похоже на запуск потока в приложении Windows Forms, где вы делаете это, чтобы пользовательский интерфейс оставался отзывчивым и не заботился о том, насколько он эффективен. В ASP.NET вас беспокоит пропускная способность , и все эти переключения контекста для всех этих рабочих потоков абсолютно убивают вашу пропускную способность, независимо от того, используете вы ThreadPool
или нет.
Пожалуйста, если вы обнаружите, что пишете код потоковой передачи в ASP.NET - подумайте, можно ли его переписать для использования уже существующих асинхронных методов, а если нет, то подумайте, действительно ли вам нужен код чтобы вообще работать в фоновом потоке. В большинстве случаев вы, вероятно, будете добавлять сложность без чистой выгоды.