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

Простое описание потоков работника и ввода-вывода в .NET.

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

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

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

Что не ясно:

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

Ответ 1

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

Термин "поток ввода-вывода" в .net/CLR относится к потокам, которые резервирует ThreadPool для отправки обратных вызовов NativeOverlapped из "перекрытых" вызовов 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

Ответ 2

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

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

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

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

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

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