С Помощью Класса ThreadPool.QueueUserWorkItem in ASP.NET в сценарии с высоким трафиком


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

Так вот как я делал небольшие асинхронные задачи до сих пор:

ThreadPool.QueueUserWorkItem(s => PostLog(logEvent))

и в статья предлагает вместо этого создать поток явно, подобно:

new Thread(() => PostLog(logEvent)){ IsBackground = true }.Start()

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

Так что мой вопрос, это совет в статья правильная?

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

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

10 108

10 ответов:

другие ответы здесь, похоже, упускают самый важный момент:

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

это касается обоих свободных потоков, созданных new Thread(...), и рабочие потоки в ThreadPool что ответить QueueUserWorkItem запросы.

Да, это правда, вы можете заморить ThreadPool в an ASP.NET процесс путем постановки в очередь слишком много рабочих элементов. Это позволит предотвратить ASP.NET с последующей обработкой запросов. Информация в статье является точной в этом отношении; тот же пул потоков, используемый для QueueUserWorkItem также используется для обслуживания запросов.

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

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

в частности, вы должны использовать асинхронные обратные вызовы, поддерживаемые любым классом библиотеки, который вы используете. Эти методы всегда очень четко обозначены; они начинаются со слов Begin и End. Как в Stream.BeginRead,Socket.BeginConnect,WebRequest.BeginGetResponse и так далее.

эти методы do использовать ThreadPool, но они используют IOCPs, которые делают не мешают ASP.NET запросы. Они представляют собой особый вид легкой нити, которая может быть "проснулся" по сигналу прерывания от системы ввода-вывода. И в Ан ASP.NET приложение, у вас обычно есть один поток ввода-вывода для каждого рабочего потока, поэтому каждый запрос может иметь одну асинхронную операцию в очереди. Это буквально сотни асинхронных операций без какого-либо значительного снижения производительности (при условии, что подсистема ввода-вывода может идти в ногу). Это намного больше, чем вам когда-либо понадобится.

просто имейте в виду, что async представители не работайте таким образом - они будут в конечном итоге используя рабочий поток, так же, как ThreadPool.QueueUserWorkItem. Это только встроенные асинхронные методы классов библиотеки .NET Framework, которые способны делать это. Вы можете сделать это сами, но это сложно и немного опасно и, вероятно, выходит за рамки этого обсуждения.

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

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

в Томас Marquadt команды ASP.NET в Microsoft, он является безопасным для использования ASP.NET пул потоков (метод queueuserworkitem).

из статьи:

Q) если мой ASP.NET приложение использует потоки CLR ThreadPool, не буду ли я голодать ASP.NET, который также использует пул потоков среды CLR для выполнения запросов? Цитата

A) [T]O резюмируйте, не беспокойтесь умираю с голоду ASP.NET ниток, а если ты думаешь ... здесь есть проблема пусть я знаю, и мы позаботимся об этом.

Q) должен ли я создавать свои собственные потоки (новая нить)? Разве это не будет лучше? ибо ASP.NET, так как он использует CLR потоки ThreadPool.

а) Пожалуйста, не надо. Или положить его по-другому, нет!!! Если вы действительно умный-гораздо умнее меня-тогда ты можно создавать свои собственные темы; в противном случае, даже не думайте об этом. Вот несколько причин, почему вы должны не часто создавайте новые темы:

1) это очень дорого, по сравнению с QueueUserWorkItem...By кстати, если вы можете написать лучший ThreadPool, чем CLR, я призываю вас подать заявку на работу в Microsoft, потому что мы определенно ищем таких людей, как вы!.

веб-сайты не должны ходить вокруг нерестовых потоков.

вы обычно перемещаете эту функцию в службу Windows, с которой вы затем общаетесь (я использую MSMQ для общения с ними).

-- Edit

Я описал реализацию здесь: фоновая обработка на основе очереди ASP.NET MVC Web Application

-- Edit

расширить, почему это даже лучше, чем просто нитки:

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

Он также позволяет пакетной обработки любой задачи, которую вы пытались сделать (отправить электронную почту/что угодно).

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

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

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

Если у вас нет проблем с производительностью, то вы решили создать новые потоки, чтобы уменьшить конкуренцию с ASP.NET очередь запросов-это классическая преждевременная оптимизация.

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

вы должны использовать QueueUserWorkItem, и избегать создания новых потоков, как вы бы избежать чумы. Для визуального, который объясняет, почему вы не будете голодать ASP.NET поскольку он использует один и тот же Тредпул, представьте себе очень опытного жонглера, использующего две руки, чтобы держать полдюжины кеглей, мечей или чего-то еще в полете. Для визуального представления о том, почему создание собственных потоков плохо, представьте, что происходит в Сиэтле в час пик, когда сильно используемые входные пандусы на шоссе позволяют автомобилям входить в трафик сразу же вместо того, чтобы использовать свет и ограничивать количество входов до одного каждые несколько секунд. Наконец, для получения подробного объяснения, пожалуйста, см. Эту ссылку:

http://blogs.msdn.com/tmarq/archive/2010/04/14/performing-asynchronous-work-or-tasks-in-asp-net-applications.aspx

спасибо, Томас

эта статья неверна. ASP.NET имеет собственный пул потоков, управляемых рабочих потоков, для обслуживания ASP.NET запросы. Этот пул обычно состоит из нескольких сотен потоков и отделен от пула ThreadPool, который является некоторым меньшим количеством процессоров.

использование ThreadPool в ASP.NET не будет мешать ASP.NET рабочие потоки. Использование ThreadPool-это нормально.

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

использование нового потока для каждого сообщения, безусловно, излишне.

Другой альтернативой, если вы говорите только о регистрации, является использование библиотеки, такой как log4net. Он обрабатывает регистрацию в отдельном потоке и заботится обо всех проблемах контекста, которые могут возникнуть в этом сценарии.

Я бы сказал, что статья неправильная. Если вы используете большой магазин .NET, вы можете безопасно использовать пул для нескольких приложений и нескольких веб-сайтов (используя отдельные пулы приложений), просто на основе одного оператора в ThreadPool документы:

есть один пул потоков для каждого процесса. Пул потоков имеет размер по умолчанию 250 рабочих потоков на существующих процессор, и завершение 1000 I/O нити. Количество потоков в нитка бассейн можно изменить с помощью метод SetMaxThreads. Каждый поток используется размер стека по умолчанию и работает при приоритете по умолчанию.

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

  1. запрос сделан на какую-то страницу
  2. Html подается обратно
  3. HTML-код сообщает клиенту, сделать дальнейшее requets (js, css, images и др..)
  4. дополнительная информация подается обратно

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

Sam также правильно в том, что использование пула потоков в среде CLR не вызовет проблем с пулом потоков в IIS. Дело однако здесь вас беспокоит то, что вы не создаете потоки из процесса, вы создаете новые потоки из потоков IIS threadpool. Есть разница, и это различие очень важно.

потоки против процесса

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

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

источник

Я не согласен с указанной статьей(C#feeds.com). легко создать новый поток, но опасно. Оптимальное количество активных потоков для работы на одном ядре на самом деле удивительно мало - менее 10. Слишком легко заставить машину тратить время на переключение потоков, если потоки создаются для второстепенных задач. Потоки-это ресурс, требующий управления. Абстракция WorkItem существует, чтобы справиться с этим.

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

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

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

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