|
| 1 | +--- |
| 2 | +title: "How to: Write a Parallel.ForEach loop with partition-local variables" |
| 3 | +ms.date: "06/26/2018" |
| 4 | +ms.technology: dotnet-standard |
| 5 | +dev_langs: |
| 6 | + - "csharp" |
| 7 | + - "vb" |
| 8 | +helpviewer_keywords: |
| 9 | + - "parallel foreach loop, how to use local state" |
| 10 | +ms.assetid: 24b10041-b30b-45cb-aa65-66cf568ca76d |
| 11 | +author: "rpetrusha" |
| 12 | +ms.author: "ronpet" |
| 13 | +--- |
| 14 | +# How to: Write a Parallel.ForEach loop with partition-local variables |
| 15 | +The following example shows how to write a <xref:System.Threading.Tasks.Parallel.ForEach%2A> method that uses partition-local variables. When a <xref:System.Threading.Tasks.Parallel.ForEach%2A> loop executes, it divides its source collection into multiple partitions. Each partition has its own copy of the partition-local variable. A partition-local variable is similar to a [thread-local variable](xref:System.Threading.ThreadLocal%601), except that multiple partitions can run on a single thread. |
| 16 | + |
| 17 | + The code and parameters in this example closely resemble the corresponding <xref:System.Threading.Tasks.Parallel.For%2A> method. For more information, see [How to: Write a Parallel.For Loop with Thread-Local Variables](../../../docs/standard/parallel-programming/how-to-write-a-parallel-for-loop-with-thread-local-variables.md). |
| 18 | + |
| 19 | + To use a partition-local variable in a <xref:System.Threading.Tasks.Parallel.ForEach%2A> loop, you must call one of the method overloads that takes two type parameters. The first type parameter, `TSource`, specifies the type of the source element, and the second type parameter, `TLocal`, specifies the type of the partition-local variable. |
| 20 | + |
| 21 | +## Example |
| 22 | + The following example calls the <xref:System.Threading.Tasks.Parallel.ForEach%60%602%28System.Collections.Generic.IEnumerable%7B%60%600%7D%2CSystem.Func%7B%60%601%7D%2CSystem.Func%7B%60%600%2CSystem.Threading.Tasks.ParallelLoopState%2C%60%601%2C%60%601%7D%2CSystem.Action%7B%60%601%7D%29?displayProperty=nameWithType> overload to compute the sum of an array of one million elements. This overload has four parameters: |
| 23 | + |
| 24 | +- `source`, which is the data source. It must implement <xref:System.Collections.Generic.IEnumerable%601>. The data source in our example is the one million member `IEnumerable<Int32>` object returned by the <xref:System.Linq.Enumerable.Range%2A?displayProperty=nameWithType> method. |
| 25 | + |
| 26 | +- `localInit`, or the function that initializes the partition-local variable. This function is called once for each partition in which the <xref:System.Threading.Tasks.Parallel.ForEach%2A?displayProperty=nameWithType> operation executes. Our example initializes the partition-local variable to zero. |
| 27 | + |
| 28 | +- `body`, a <xref:System.Func%604> that is invoked by the parallel loop on each iteration of the loop. Its signature is `Func\<TSource, ParallelLoopState, TLocal, TLocal>`. You supply the code for the delegate, and the loop passes in the input parameters, which are: |
| 29 | + |
| 30 | + - The current element of the <xref:System.Collections.Generic.IEnumerable%601>. |
| 31 | + |
| 32 | + - A <xref:System.Threading.Tasks.ParallelLoopState> variable that you can use in your delegate's code to examine the state of the loop. |
| 33 | + |
| 34 | + - The partition-local variable. |
| 35 | + |
| 36 | + Your delegate returns the partition-local variable, which is then passed to the next iteration of the loop that executes in that particular partition. Each loop partition maintains a separate instance of this variable. |
| 37 | + |
| 38 | + In the example, the delegate adds the value of each integer to the partition-local variable, which maintains a running total of the values of the integer elements in that partition. |
| 39 | + |
| 40 | +- `localFinally`, an `Action<TLocal>` delegate that the <xref:System.Threading.Tasks.Parallel.ForEach%2A?displayProperty=nameWithType> invokes when the looping operations in each partition have completed. The <xref:System.Threading.Tasks.Parallel.ForEach%2A?displayProperty=nameWithType> method passes your `Action<TLocal>` delegate the final value of the partition-local variable for this loop partition, and you provide the code that performs the required action for combining the result from this partition with the results from the other partitions. This delegate can be invoked concurrently by multiple tasks. Because of this, the example uses the <xref:System.Threading.Interlocked.Add%28System.Int32%40%2CSystem.Int32%29?displayProperty=nameWithType> method to synchronize access to the `total` variable. Because the delegate type is an <xref:System.Action%601>, there is no return value. |
| 41 | + |
| 42 | + [!code-csharp[TPL_Parallel#04](../../../samples/snippets/csharp/VS_Snippets_Misc/tpl_parallel/cs/foreachthreadlocal.cs#04)] |
| 43 | + [!code-vb[TPL_Parallel#04](../../../samples/snippets/visualbasic/VS_Snippets_Misc/tpl_parallel/vb/foreachthreadlocal.vb#04)] |
| 44 | + |
| 45 | +## See Also |
| 46 | + [Data Parallelism](../../../docs/standard/parallel-programming/data-parallelism-task-parallel-library.md) |
| 47 | + [How to: Write a Parallel.For Loop with Thread-Local Variables](../../../docs/standard/parallel-programming/how-to-write-a-parallel-for-loop-with-thread-local-variables.md) |
| 48 | + [Lambda Expressions in PLINQ and TPL](../../../docs/standard/parallel-programming/lambda-expressions-in-plinq-and-tpl.md) |
0 commit comments