Создание и уничтожение потока — довольно
дорогая операция в плане временных затрат. Кроме того, при наличии множества потоков впустую расходуется память и ухудшается производительность из-за того, что ОС должна планировать потоки и выполнять переключения контекста между потоками, готовыми к выполнению.
К счастью, в CLR есть код для управления собственным пулом потоков. Пул потоков можно рассматривать как набор потоков, доступных для использования приложением.
У каждого процесса есть один
пул потоков, который используется всеми доменами AppDomain этого процесса.
По завершении своей задачи
поток из пула не уничтожается, а
возвращается в пул и ожидает следующего запроса.
Поскольку поток не уничтожается, производительность от этого не страдает.
Класс
System.Threading.ThreadPool обеспечивает приложение пулом рабочих потоков, управляемых системой, позволяя пользователю сосредоточиться на выполнении задач приложения, а не на управлении потоками.
Если имеются небольшие задачи, которые требуют фоновой обработки,
пул управляемых потоков — это самый простой способ воспользоваться потоков.
В Framework 4 и более поздних версиях использовать пул потоков стало значительно проще, так как вы можете создавать объекты
Task и
Task<TResult>, которые выполняют в
потоках пула асинхронные задачи.
Платформа .NET использует
потоки из
пула в различных целях, в том числе для операций
библиотеки параллельных задач (TPL), асинхронного ввода-вывода, обратных вызовов таймера, регистрируемых операций ожидания, асинхронного вызова методов с использованием делегатов и для подключения к сокетам System.Net.
Характеристики пула потоков
Потоки из пула являются
фоновыми. Для каждого потока используется размер стека по умолчанию, поток запускается с приоритетом по умолчанию и находится в многопотоковом подразделении. Когда поток в пуле завершает свою задачу, он возвращается в очередь потоков в состоянии ожидания. С этого момента его можно использовать вновь. Повторное использование позволяет приложениям избежать дополнительных затрат на создание новых потоков для каждой задачи.
Для каждого
процесса существует только один
пул потоков.
Необработанные исключения в потоках из пула приводят к завершению процесса. Существует три исключения из этого правила:
• Исключение
System.Threading.ThreadAbortException возникает в потоке пула вследствие вызова
Thread.Abort.
• Исключение
возникает в потоке пула вследствие выгрузки домена приложения.
• Среда CLR или процесс ведущего приложения прерывает выполнение потока.
Пул потоков имеет ограничение на число потоков, которое можно активировать в процессе одновременно. Если все потоки в пуле заняты, дополнительные рабочие элементы помещаются в очередь и ожидают их освобождения.
Число операций, которое можно поставить в очередь в
пуле потоков, ограничено только доступной памятью.
Начиная с .NET Framework 4,
размер пула потоков по умолчанию для какого-либо процесса зависит от нескольких факторов, таких как размер виртуального адресного пространства.
Процесс может вызвать метод
ThreadPool.GetMaxThreads для определения количества потоков.
Вы можете управлять максимальным количеством потоков с помощью методов
ThreadPool.GetMaxThreads и
ThreadPool.SetMaxThreads.