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

Объединение потоков в пул является формой многопоточности, при которой задачи добавляются в очередь и автоматически запускаются при создании новых потоков. Дополнительные сведения см. в разделе Группировка потоков в пул (C# и Visual Basic).

В следующем примере пул потоков .NET Framework используется для вычисления результата Fibonacci для десяти чисел в интервале от 20 до 40. Каждый результат Fibonacci представляется классом Fibonacci, который предоставляет метод ThreadPoolCallback, выполняющий вычисления. Создается объект, представляющий каждое значение Fibonacci, и метод ThreadPoolCallback передается в элемент QueueUserWorkItem, который назначает выполнение метода доступному потоку из пула.

Поскольку каждому объекту Fibonacci назначается для вычисления полупроизвольное значение, и все потоки соревнуются за ресурсы процессора, невозможно заранее сказать. сколько времени понадобится на вычисление всех десяти значений. Именно поэтому каждый объект Fibonacci передается в экземпляр класса ManualResetEvent во время конструирования. Каждый объект сигнализирует соответствующему объекту события о завершении вычисления, что позволяет главному потоку блокировать выполнение WaitAll до завершения вычисления результата всех десяти объектов Fibonacci. После этого метод Main отображает все результаты Fibonacci.

Пример

Imports System.Threading

Module Module1

    Public Class Fibonacci
        Private _n As Integer 
        Private _fibOfN
        Private _doneEvent As ManualResetEvent

        Public ReadOnly Property N() As Integer 
            Get 
                Return _n
            End Get 
        End Property 

        Public ReadOnly Property FibOfN() As Integer 
            Get 
                Return _fibOfN
            End Get 
        End Property 

        Sub New(ByVal n As Integer, ByVal doneEvent As ManualResetEvent)
            _n = n
            _doneEvent = doneEvent
        End Sub 

        ' Wrapper method for use with the thread pool. 
        Public Sub ThreadPoolCallBack(ByVal threadContext As Object)
            Dim threadIndex As Integer = CType(threadContext, Integer)
            Console.WriteLine("thread {0} started...", threadIndex)
            _fibOfN = Calculate(_n)
            Console.WriteLine("thread {0} result calculated...", threadIndex)
            _doneEvent.Set()
        End Sub 

        Public Function Calculate(ByVal n As Integer) As Integer 
            If n <= 1 Then 
                Return n
            End If 
            Return Calculate(n - 1) + Calculate(n - 2)
        End Function 

    End Class


    <MTAThread()> 
    Sub Main()
        Const FibonacciCalculations As Integer = 9 ' 0 to 9

        ' One event is used for each Fibonacci object 
        Dim doneEvents(FibonacciCalculations) As ManualResetEvent
        Dim fibArray(FibonacciCalculations) As Fibonacci
        Dim r As New Random()

        ' Configure and start threads using ThreadPool.
        Console.WriteLine("launching {0} tasks...", FibonacciCalculations)

        For i As Integer = 0 To FibonacciCalculations
            doneEvents(i) = New ManualResetEvent(False)
            Dim f = New Fibonacci(r.Next(20, 40), doneEvents(i))
            fibArray(i) = f
            ThreadPool.QueueUserWorkItem(AddressOf f.ThreadPoolCallBack, i)
        Next 

        ' Wait for all threads in pool to calculate.
        WaitHandle.WaitAll(doneEvents)
        Console.WriteLine("All calculations are complete.")

        ' Display the results. 
        For i As Integer = 0 To FibonacciCalculations
            Dim f As Fibonacci = fibArray(i)
            Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN)
        Next 
    End Sub 

End Module
using System;
using System.Threading;

public class Fibonacci
{
    private int _n;
    private int _fibOfN;
    private ManualResetEvent _doneEvent;

    public int N { get { return _n; } }
    public int FibOfN { get { return _fibOfN; } }

    // Constructor. 
    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 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 start 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 calculate.
        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...
thread 0 started...
thread 1 started...
thread 1 result calculated...
thread 2 started...
thread 2 result calculated...
thread 3 started...
thread 3 result calculated...
thread 4 started...
thread 0 result calculated...
thread 5 started...
thread 5 result calculated...
thread 6 started...
thread 4 result calculated...
thread 7 started...
thread 6 result calculated...
thread 8 started...
thread 8 result calculated...
thread 9 started...
thread 9 result calculated...
thread 7 result calculated...
All calculations are complete.
Fibonacci(38) = 39088169
Fibonacci(29) = 514229
Fibonacci(25) = 75025
Fibonacci(22) = 17711
Fibonacci(38) = 39088169
Fibonacci(29) = 514229
Fibonacci(29) = 514229
Fibonacci(38) = 39088169
Fibonacci(21) = 10946
Fibonacci(27) = 196418

См. также

Ссылки

Mutex

WaitAll

ManualResetEvent

Set

ThreadPool

QueueUserWorkItem

ManualResetEvent

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

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

Мониторы

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

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

Синхронизация доступа к общим ресурсам в многопоточной среде с использованием Visual C# .NET

Безопасность в .NET Framework