Практическое руководство. Использование пула потоков (руководство по программированию на C#)
Обновлен: Ноябрь 2007
Пул потоков — это коллекция потоков, которые могут использоваться для выполнения нескольких задач в фоновом режиме. (Дополнительные сведения см. в разделе Использование потоков (Руководство по программированию на C#).) Это позволяет разгрузить главный поток для асинхронного выполнения других задач.
Пулы потоков часто используются в серверных приложениях. Каждый входящий запрос назначается потоку из пула, таким образом, запрос может обрабатываться асинхронно без задействования главного потока и задержки обработки последующих запросов.
Когда поток в пуле завершает выполнение задачи, он возвращается в очередь ожидания, в которой может быть повторно использован. Повторное использование позволяет приложениям избежать дополнительных затрат на создание новых потоков для каждой задачи.
Обычно пулы имеют максимальное количество потоков. Если все потоки заняты, дополнительные задачи помещаются в очередь, где хранятся до тех пор, пока не появятся свободные потоки.
Можно реализовать собственный пул потоков, но гораздо проще использовать пул, предоставляемый .NET Framework через класс ThreadPool.
В следующем примере пул потоков .NET Framework используется для вычисления результата Fibonacci для десяти чисел от 20 до 40. Каждый результат Fibonacci представляется классом Fibonacci, который предоставляет метод ThreadPoolCallback, выполняющий вычисление. Создается объект, представляющий каждое значение Fibonacci, и метод ThreadPoolCallback передается в элемент QueueUserWorkItem, который назначает выполнение метода доступному потоку из пула.
Поскольку каждому объекту Fibonacci назначается для вычисления полупроизвольное значение, и все потоки соревнуются за ресурсы процессора, невозможно заранее сказать. сколько времени понадобится на вычисление всех десяти значений. Именно поэтому каждый объект Fibonacci передается в экземпляр класса ManualResetEvent во время конструирования. Каждый объект сигнализирует соответствующему объекту события о завершении вычисления, что позволяет главному потоку блокировать выполнение WaitAll до завершения вычисления результата всех десяти объектов Fibonacci. После этого метод Main отображает все результаты Fibonacci.
Пример
using System;
using System.Threading;
public class Fibonacci
{
public Fibonacci(int n, ManualResetEvent doneEvent)
{
_n = n;
_doneEvent = doneEvent;
}
// Wrapper method for use with thread pool.
public void ThreadPoolCallback(Object threadContext)
{
int threadIndex = (int)threadContext;
Console.WriteLine("thread {0} started...", threadIndex);
_fibOfN = Calculate(_n);
Console.WriteLine("thread {0} result calculated...", threadIndex);
_doneEvent.Set();
}
// Recursive method that calculates the Nth Fibonacci number.
public int Calculate(int n)
{
if (n <= 1)
{
return n;
}
return Calculate(n - 1) + Calculate(n - 2);
}
public int N { get { return _n; } }
private int _n;
public int FibOfN { get { return _fibOfN; } }
private int _fibOfN;
private ManualResetEvent _doneEvent;
}
public class ThreadPoolExample
{
static void Main()
{
const int FibonacciCalculations = 10;
// One event is used for each Fibonacci object
ManualResetEvent[] doneEvents = new ManualResetEvent[FibonacciCalculations];
Fibonacci[] fibArray = new Fibonacci[FibonacciCalculations];
Random r = new Random();
// Configure and launch threads using ThreadPool:
Console.WriteLine("launching {0} tasks...", FibonacciCalculations);
for (int i = 0; i < FibonacciCalculations; i++)
{
doneEvents[i] = new ManualResetEvent(false);
Fibonacci f = new Fibonacci(r.Next(20,40), doneEvents[i]);
fibArray[i] = f;
ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i);
}
// Wait for all threads in pool to calculation...
WaitHandle.WaitAll(doneEvents);
Console.WriteLine("All calculations are complete.");
// Display the results...
for (int i= 0; i<FibonacciCalculations; i++)
{
Fibonacci f = fibArray[i];
Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN);
}
}
}
Ниже приведены выходные данные.
launching 10 tasks...
result calculated...
result calculated...
result calculated...
result calculated...
result calculated...
result calculated...
result calculated...
result calculated...
result calculated...
result calculated...
all calculations complete
Fibonacci(22) = 17711
Fibonacci(25) = 75025
Fibonacci(32) = 2178309
Fibonacci(36) = 14930352
Fibonacci(32) = 2178309
Fibonacci(26) = 121393
Fibonacci(35) = 9227465
Fibonacci(23) = 28657
Fibonacci(39) = 63245986
Fibonacci(22) = 17711
См. также
Задачи
Пример Monitor Synchronization Technology
Пример Wait Synchronization Technology
Основные понятия
Руководство по программированию в C#
Ссылки
Создание потоков (Руководство по программированию на C#)
Использование потоков (Руководство по программированию на C#)