День сто восемьдесят первый. #ЗаметкиНаПолях

Многопоточность.

2. Пул потоков в CLR

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

В пуле различают два типа потоков: рабочие потоки (worker thread) и потоки ввода-вывода (I/O thread). Первые используются для асинхронных вычислительных операций, вторые служат для уведомления кода о завершении асинхронной операции ввода-вывода.

Для добавления в очередь пула потоков асинхронных вычислительных операций обычно вызывают один из методов QueueUserWorkItem класса ThreadPool. В метод передаётся делегат WaitCallback, а также может передаваться объект состояния state:

static void Main(string[] args)

{

Console.WriteLine("Основной поток: вызываем асинхронную операцию");

ThreadPool.QueueUserWorkItem(Compute, 5);

Console.WriteLine("Основной поток: выполняем другую работу...");

Thread.Sleep(10000);

Console.ReadLine();

}



private static void Compute(object state)

{

//Метод выполняется потоком из пула

Console.WriteLine($"В Compute: state={state}");

Thread.Sleep(1000);

}

После возвращения управления асинхронным методом, поток возвращается в пул и ожидает следующего задания.



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

- Поток требуется запустить с нестандартным приоритетом (хотя, этого делать не рекомендуется).

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

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

- Если есть необходимость преждевременно завершить исполняющийся поток через Thread.Abort().



Продолжение следует…



Источник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 26.