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