Простое описание рабочих и потоков ввода / вывода в .NET - PullRequest
55 голосов
/ 20 января 2010

Очень сложно найти подробное, но простое описание рабочих потоков и потоков ввода / вывода в .NET

Что мне ясно по этой теме (но может быть неточно технически):

  • Рабочие потоки - это потоки, которые должны использовать ЦП для своей работы;
  • Потоки ввода / вывода (также называемые "потоками портов завершения") должны использовать драйверы устройств для своей работы и, по сути, "ничего не делать", только следить за завершением операций без использования процессора.

Что не понятно:

  • Хотя метод ThreadPool.GetAvailableThreads возвращает количество доступных потоков обоих типов, похоже, что нет общедоступного API для планирования работы для потока ввода-вывода. Вы можете только вручную создать рабочий поток в .NET?
  • Кажется, что один поток ввода-вывода может контролировать несколько операций ввода-вывода. Это правда? Если да, то почему у ThreadPool по умолчанию так много доступных потоков ввода-вывода?
  • В некоторых текстах я читал этот обратный вызов, который запускается после выполнения операции ввода-вывода потоком ввода-вывода. Это правда? Разве это не работа для рабочего потока, учитывая, что этот обратный вызов является операцией процессора?
  • Если быть более конкретным - делают ли асинхронные страницы ASP.NET пользовательскими потоками ввода-вывода? Что именно повышает производительность при переключении работы ввода-вывода в отдельный поток вместо увеличения максимального числа рабочих потоков? Это потому, что один поток ввода-вывода контролирует несколько операций? Или Windows делает более эффективное переключение контекста при использовании потоков ввода / вывода?

Ответы [ 4 ]

63 голосов
/ 30 января 2010

Термин «рабочий поток» в .net / CLR обычно относится только к любому потоку, кроме основного потока, который выполняет некоторую «работу» от имени приложения, породившего поток.«Работа» может означать что угодно, включая ожидание завершения ввода-вывода.ThreadPool хранит кэш рабочих потоков, поскольку создавать потоки дорого.

Термин «поток ввода-вывода» в .net / CLR относится к потокам, резервируемым ThreadPool для отправки обратных вызовов NativeOverlapped из «перекрывающихся».msgstr "вызовы win32 (также известные как" завершение ввода / вывода порта ").CLR поддерживает свой собственный порт завершения ввода / вывода и может привязывать к нему любой дескриптор (через API ThreadPool.BindHandle).Пример здесь: http://blogs.msdn.com/junfeng/archive/2008/12/01/threadpool-bindhandle.aspx. Многие API .net используют этот механизм для получения обратных вызовов NativeOverlapped, хотя типичный разработчик .net никогда не использует его напрямую.

Технических различий между ними нет 'рабочий поток »и« поток ввода-вывода »- они оба являются обычными потоками.Но CLR ThreadPool хранит отдельные пулы каждого из них просто для того, чтобы избежать ситуации, когда высокий спрос на рабочие потоки исчерпывает все доступные потоки для отправки собственных обратных вызовов ввода-вывода, что может привести к тупиковой ситуации.(Представьте себе приложение, использующее все 250 рабочих потоков, каждый из которых ожидает завершения ввода-вывода).

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

Несколько полезных ссылок для дальнейшего чтения: ввод-вывод win32порты завершения: http://msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx пул управляемых потоков: http://msdn.microsoft.com/en-us/library/0ka9477y.aspx пример BindHandle: http://blogs.msdn.com/junfeng/archive/2008/12/01/threadpool-bindhandle.aspx

8 голосов
/ 20 января 2010

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

Возможно, вы знакомы с функцией Win32 API ReadFile (как пример), которая является оберткой вокруг функции Native API NtReadFile .Эта функция позволяет выполнять две операции с асинхронным вводом / выводом:

  • . Вы можете создать объект события и передать его NtReadFile .Затем об этом событии будет сообщено по завершении операции чтения.
  • Вы можете передать функцию асинхронного вызова процедуры (APC) в NtReadFile .По сути, это означает, что после завершения операции чтения функция будет поставлена ​​в очередь в потоке, который инициировал операцию, и будет выполнена, когда поток выполнит предупреждающее ожидание .

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

Обычный «рабочий поток» очень похож;вместо удаления результатов ввода-вывода из очереди он удаляет рабочие элементы из очереди.Вы можете поставить в очередь рабочие элементы ( QueueUserWorkItem ) и заставить их выполнять рабочие потоки.Это избавляет вас от необходимости порождать поток каждый раз, когда вы хотите выполнить задачу асинхронно.

3 голосов
/ 20 января 2010

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

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

Все процессы выполняются как потоки. Ваше приложение работает как поток. Любой поток может порождать рабочие потоки или потоки ввода / вывода (как вы их называете).

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

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

0 голосов
/ 20 января 2010

Кто-то, у кого больше навыков, чем у меня, собирается выскочить сюда, чтобы помочь.

Рабочие потоки имеют большое состояние, они планируются процессором и т. Д., И вы контролируете все, что они делают.

Порты завершения ввода-вывода предоставляются операционной системой для очень специфических задач, связанных с небольшим общим состоянием, и, следовательно, быстрее в использовании.Хорошим примером в .Net является структура WCF.Каждый «вызов» к службе WCF фактически выполняется портом завершения ввода-вывода, потому что они запускаются быстрее всего, а ОС присматривает за ними.

...