방법: 파티션-로컬 변수를 사용하여 Parallel.ForEach 루프 작성
다음 예제에서는 파티션-지역 변수를 사용하는 ForEach 메서드를 작성하는 방법을 보여 줍니다. ForEach 루프가 실행되면 원본 컬렉션을 여러 파티션으로 나눕니다. 각 파티션에는 파티션-지역 변수의 자체 복사본이 있습니다. 파티션-로컬 변수는 단일 스레드에서 여러 파티션을 실행할 수 있다는 점을 제외하고 스레드-지역 변수비슷합니다.
이 예제의 코드 및 매개 변수는 해당 For 메서드와 매우 유사합니다. 자세한 내용은 방법: Thread-Local 변수사용하여 Parallel.For 루프 작성을 참조하세요.
ForEach 루프에서 파티션 지역 변수를 사용하려면 두 가지 형식 매개 변수를 사용하는 메서드 오버로드 중 하나를 호출해야 합니다. 첫 번째 형식 매개 변수인 TSource
소스 요소의 형식을 지정하고 두 번째 형식 매개 변수인 TLocal
파티션-지역 변수의 형식을 지정합니다.
예시
다음 예제에서는 Parallel.ForEach<TSource,TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) 오버로드를 호출하여 백만 개의 요소 배열의 합계를 계산합니다. 이 오버로드에는 다음 네 개의 매개 변수가 있습니다.
데이터 원본인
source
. IEnumerable<T>구현해야 합니다. 이 예제의 데이터 원본은 Enumerable.Range 메서드에서 반환된 백만 멤버IEnumerable<Int32>
개체입니다.localInit
또는 파티션-지역 변수를 초기화하는 함수입니다. 이 함수는 Parallel.ForEach 작업이 실행되는 각 파티션에 대해 한 번 호출됩니다. 이 예제에서는 파티션-지역 변수를 0으로 초기화합니다.body
루프의 각 반복에서 병렬 루프에 의해 호출되는 Func<T1,T2,T3,TResult>. 서명은Func\<TSource, ParallelLoopState, TLocal, TLocal>
. 대리자의 코드를 제공하면 루프가 입력 매개 변수를 전달합니다.IEnumerable<T>의 현재 요소입니다.
대리자의 코드에서 루프의 상태를 검사하는 데 사용할 수 있는 ParallelLoopState 변수입니다.
파티션-지역 변수입니다.
대리자는 파티션-지역 변수를 반환한 다음, 해당 특정 파티션에서 실행되는 루프의 다음 반복으로 전달됩니다. 각 루프 파티션은 이 변수의 별도 인스턴스를 유지 관리합니다.
이 예제에서 대리자는 파티션-지역 변수에 각 정수 값을 추가합니다. 이 변수는 해당 파티션에 있는 정수 요소 값의 총계를 유지 관리합니다.
localFinally
은(는) 각 파티션의 반복 작업이 완료되었을 때 Parallel.ForEach가 호출하는Action<TLocal>
대리자입니다. 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 {total:N0}");
}
}
// 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
참고하십시오
.NET