Группировка потоков в пул (C# и Visual Basic)

Пул потоков — это коллекция потоков, которые могут использоваться для выполнения нескольких задач в фоновом режиме. (Дополнительные сведения см. в разделе Работа с потоками (C# и Visual Basic).) Это позволяет разгрузить главный поток для асинхронного выполнения других задач.

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

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

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

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

Используя группировку потоков в пул, можно вызвать метод ThreadPool.QueueUserWorkItem с делегатом для процедуры, которую требуется выполнить, а Visual Basic или C# создаст поток и выполнит процедуру.

Пример группировки потоков в пул

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

Public Sub DoWork()
    ' Queue a task.
    System.Threading.ThreadPool.QueueUserWorkItem(
        New System.Threading.WaitCallback(AddressOf SomeLongTask))
    ' Queue another task.
    System.Threading.ThreadPool.QueueUserWorkItem(
        New System.Threading.WaitCallback(AddressOf AnotherLongTask))
End Sub 
Private Sub SomeLongTask(ByVal state As Object)
    ' Insert code to perform a long task. 
End Sub 
Private Sub AnotherLongTask(ByVal state As Object)
    ' Insert code to perform another long task. 
End Sub
public void DoWork()
{
    // Queue a task.
    System.Threading.ThreadPool.QueueUserWorkItem(
        new System.Threading.WaitCallback(SomeLongTask));
    // Queue another task.
    System.Threading.ThreadPool.QueueUserWorkItem(
        new System.Threading.WaitCallback(AnotherLongTask));
}

private void SomeLongTask(Object state)
{
    // Insert code to perform a long task.
}

private void AnotherLongTask(Object state)
{
    // Insert code to perform a long task.
}

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

Параметры и возвращаемые значения пула потоков

Получение возвращаемого значения из пула потоков является не такой простой задачей. Стандартный способ получения возвращаемого значения при вызове функции использовать нельзя, поскольку помещать в очередь на выполнение в пуле потоков можно только процедуры Sub. Один из способов обеспечить передачу параметров и возвращения значений — это заключение параметров, возвращаемых значений и методов в класс-оболочку (см. раздел Параметры и возвращаемые значения для многопоточных процедур (C# и Visual Basic)).

Более простым способом передачи параметров и возвращаемых значений является использование необязательной переменной состояния объекта типа ByVal метода QueueUserWorkItem. Если эта переменная используется для передачи ссылки на экземпляр класса, члены экземпляра могут быть изменены потоком, входящим в пул потоков, и использоваться в качестве возвращаемых значений.

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

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

См. также

Задачи

Практическое руководство. Использование пула потоков (C# и Visual Basic)

Ссылки

Синхронизация потоков (C# и Visual Basic)

QueueUserWorkItem

System.Threading

ThreadPool

Основные понятия

Многопоточные приложения (C# и Visual Basic)

Другие ресурсы

Работа с потоками (C# и Visual Basic)

Как передать рабочий объект в потоковый пул, используя Visual C# .NET