다음을 통해 공유


방법: 파티션 로컬 변수를 사용하는 Parallel.ForEach 루프 작성

다음 예제에서는 파티션 지역 변수를 사용하는 ForEach 메서드를 작성하는 방법을 보여줍니다. ForEach 루프가 실행되면 해당 소스 컬렉션이 여러 파티션으로 나뉩니다. 각 파티션에는 고유한 파티션 지역 변수의 복사본이 있습니다. 파티션 지역 변수는 여러 파티션이 단일 스레드에서 실행될 수 있다는 점을 제외하고 스레드 지역 변수와 유사합니다.

이 예제의 코드와 매개 변수는 해당 For 메서드와 매우 흡사합니다. 자세한 내용은 방법: 스레드 로컬 변수를 사용하는 Parallel.For 루프 작성을 참조하세요.

ForEach 루프에서 파티션 지역 변수를 사용하려면 두 가지 형식의 매개 변수를 사용하는 메서드 오버로드 중 하나를 호출해야 합니다. 첫 번째 형식 매개 변수인 TSource는 원본 요소의 형식을 지정하고, 두 번째 형식 매개 변수인 TLocal은 파티션 로컬 변수의 형식을 지정합니다.

예시

다음 예제에서는 Parallel.ForEach<TSource,TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) 오버로드를 호출하여 1백만 개의 요소가 포함된 배열의 합계를 컴퓨팅합니다. 이 오버로드에는 다음과 같은 4개의 매개 변수가 있습니다.

  • source: 데이터 소스이며, IEnumerable<T>를 구현해야 합니다. 이 예제에서 데이터 소스는 IEnumerable<Int32> 메서드에서 반환된 1백만 개의 멤버 Enumerable.Range 개체입니다.

  • localInit 또는 파티션 지역 변수를 초기화하는 함수입니다. 이 함수는 Parallel.ForEach 작업이 실행되는 각 파티션에 대해 한 번 호출됩니다. 이 예제에서는 파티션 지역 변수를 0으로 초기화합니다.

  • body: 루프가 반복될 때마다 병렬 루프에 의해 호출되는 Func<T1,T2,T3,TResult>입니다. 해당 시그니처는 Func\<TSource, ParallelLoopState, TLocal, TLocal>입니다. 사용자는 대리자의 코드를 제공하고, 루프는 다음과 같은 입력 매개 변수를 전달합니다.

    • IEnumerable<T>의 현재 요소

    • 루프의 상태를 검토하기 위해 대리자 코드에 사용할 수 있는 ParallelLoopState 변수

    • 파티션 지역 변수입니다.

    대리자는 파티션 지역 변수를 반환한 다음, 스레드 지역 변수는 해당 특정 파티션에서 실행되는 루프의 다음 반복으로 전달됩니다. 각 루프 파티션에서는 이 변수의 별도의 인스턴스를 유지합니다.

    이 예제에서는 대리자가 각 정수 값을 파티션 지역 변수에 더하고, 파티션 지역 변수는 해당 파티션에서 정수 요소 값의 누계를 유지합니다.

  • localFinally: 각 파티션의 루프 작업이 완료될 때 Action<TLocal>가 호출하는 Parallel.ForEach 대리자입니다. Parallel.ForEach 메서드는 이 루프 파티션에 대한 파티션 지역 변수의 최종 값을 Action<TLocal> 대리자에게 전달하고, 사용자는 이 파티션의 결과를 다른 파티션의 결과와 결합하는 데 필요한 작업을 수행하는 코드를 제공합니다. 이 대리자는 여러 작업에서 동시에 호출할 수 있습니다. 그렇기 때문에 이 예제에서는 Interlocked.Add(Int32, Int32) 메서드를 사용하여 total 변수에 대한 액세스를 동기화합니다. 대리자 형식이 Action<T>이므로 반환 값은 없습니다.

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

class Test
{
    static void Main()
    {
        int[] nums = Enumerable.Range(0, 1000000).ToArray();
        long total = 0;

        // First type parameter is the type of the source elements
        // Second type parameter is the type of the thread-local variable (partition subtotal)
        Parallel.ForEach<int, long>(
            nums, // source collection
            () => 0, // method to initialize the local variable
            (j, loop, subtotal) => // method invoked by the loop on each iteration
            {
                subtotal += j; //modify local variable
                return subtotal; // value to be passed to next iteration
            },
            // Method to be executed when each partition has completed.
            // finalResult is the final value of subtotal for a particular partition.
            (finalResult) => Interlocked.Add(ref total, finalResult));

        Console.WriteLine("The total from Parallel.ForEach is {0:N0}", total);
    }
}
// The example displays the following output:
//        The total from Parallel.ForEach is 499,999,500,000
' How to: Write a Parallel.ForEach Loop That Has Thread-Local Variables

Imports System.Threading
Imports System.Threading.Tasks

Module ForEachThreadLocal
    Sub Main()

        Dim nums() As Integer = Enumerable.Range(0, 1000000).ToArray()
        Dim total As Long = 0

        ' First type parameter is the type of the source elements
        ' Second type parameter is the type of the thread-local variable (partition subtotal)
        Parallel.ForEach(Of Integer, Long)(nums, Function() 0,
                                           Function(elem, loopState, subtotal)
                                               subtotal += elem
                                               Return subtotal
                                           End Function,
                                            Sub(finalResult)
                                                Interlocked.Add(total, finalResult)
                                            End Sub)

        Console.WriteLine("The result of Parallel.ForEach is {0:N0}", total)
    End Sub
End Module
' The example displays the following output:
'       The result of Parallel.ForEach is 499,999,500,000

참고 항목