Skip to content

Commit 9ba0a96

Browse files
author
Ron Petrusha
authored
Changed thread-local to partition-local (#6132)
1 parent ff88268 commit 9ba0a96

7 files changed

+58
-53
lines changed

.openpublishing.redirection.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,12 @@
941941
"source_path": "docs/standard/microservices-architecture/architect-microservice-container-applications/communication-between-microservices.md",
942942
"redirect_url": "/dotnet/standard/microservices-architecture/architect-microservice-container-applications/communication-in-microservice-architecture",
943943
"redirect_document_id": true
944-
},
944+
},
945+
{
946+
"source_path": "docs/standard/parallel-programming/how-to-write-a-parallel-foreach-loop-with-thread-local-variables.md",
947+
"redirect_url": "/dotnet/standard/parallel-programming/how-to-write-a-parallel-foreach-loop-with-partition-local-variables",
948+
"redirect_document_id": true
949+
},
945950
{
946951
"source_path": "docs/standard/serialization/marshal-by-value.md",
947952
"redirect_url": "/dotnet/standard/serialization-concepts"

docs/framework/performance/lazy-initialization.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ ms.author: "ronpet"
134134
[!code-vb[Lazy#9](../../../samples/snippets/visualbasic/VS_Snippets_Misc/lazy/vb/lazy_vb.vb#9)]
135135

136136
## Thread-Local Variables in Parallel.For and ForEach
137-
When you use the <xref:System.Threading.Tasks.Parallel.For%2A?displayProperty=nameWithType> method or <xref:System.Threading.Tasks.Parallel.ForEach%2A?displayProperty=nameWithType> method to iterate over data sources in parallel, you can use the overloads that have built-in support for thread-local data. In these methods, the thread-locality is achieved by using local delegates to create, access, and clean up the data. 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) and [How to: Write a Parallel.ForEach Loop with Thread-Local Variables](../../../docs/standard/parallel-programming/how-to-write-a-parallel-foreach-loop-with-thread-local-variables.md).
137+
When you use the <xref:System.Threading.Tasks.Parallel.For%2A?displayProperty=nameWithType> method or <xref:System.Threading.Tasks.Parallel.ForEach%2A?displayProperty=nameWithType> method to iterate over data sources in parallel, you can use the overloads that have built-in support for thread-local data. In these methods, the thread-locality is achieved by using local delegates to create, access, and clean up the data. 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) and [How to: Write a Parallel.ForEach Loop with Partition-Local Variables](../../../docs/standard/parallel-programming/how-to-write-a-parallel-foreach-loop-with-partition-local-variables.md).
138138

139139
## Using Lazy Initialization for Low-Overhead Scenarios
140140
In scenarios where you have to lazy-initialize a large number of objects, you might decide that wrapping each object in a <xref:System.Lazy%601> requires too much memory or too many computing resources. Or, you might have stringent requirements about how lazy initialization is exposed. In such cases, you can use the `static` (`Shared` in Visual Basic) methods of the <xref:System.Threading.LazyInitializer?displayProperty=nameWithType> class to lazy-initialize each object without wrapping it in an instance of <xref:System.Lazy%601>.

docs/standard/parallel-programming/data-parallelism-task-parallel-library.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ ms.author: "ronpet"
4141
|[How to: Write a Simple Parallel.ForEach Loop](../../../docs/standard/parallel-programming/how-to-write-a-simple-parallel-foreach-loop.md)|Describes how to write a <xref:System.Threading.Tasks.Parallel.ForEach%2A> loop over any <xref:System.Collections.Generic.IEnumerable%601> source collection.|
4242
|[How to: Stop or Break from a Parallel.For Loop](https://msdn.microsoft.com/library/de52e4f1-9346-4ad5-b582-1a4d54dc7f7e)|Describes how to stop or break from a parallel loop so that all threads are informed of the action.|
4343
|[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)|Describes how to write a <xref:System.Threading.Tasks.Parallel.For%2A> loop in which each thread maintains a private variable that is not visible to any other threads, and how to synchronize the results from all threads when the loop completes.|
44-
|[How to: Write a Parallel.ForEach Loop with Thread-Local Variables](../../../docs/standard/parallel-programming/how-to-write-a-parallel-foreach-loop-with-thread-local-variables.md)|Describes how to write a <xref:System.Threading.Tasks.Parallel.ForEach%2A> loop in which each thread maintains a private variable that is not visible to any other threads, and how to synchronize the results from all threads when the loop completes.|
44+
|[How to: Write a Parallel.ForEach Loop with Partition-Local Variables](../../../docs/standard/parallel-programming/how-to-write-a-parallel-foreach-loop-with-partition-local-variables.md)|Describes how to write a <xref:System.Threading.Tasks.Parallel.ForEach%2A> loop in which each thread maintains a private variable that is not visible to any other threads, and how to synchronize the results from all threads when the loop completes.|
4545
|[How to: Cancel a Parallel.For or ForEach Loop](../../../docs/standard/parallel-programming/how-to-cancel-a-parallel-for-or-foreach-loop.md)|Describes how to cancel a parallel loop by using a <xref:System.Threading.CancellationToken?displayProperty=nameWithType>|
4646
|[How to: Speed Up Small Loop Bodies](../../../docs/standard/parallel-programming/how-to-speed-up-small-loop-bodies.md)|Describes one way to speed up execution when a loop body is very small.|
4747
|[Task Parallel Library (TPL)](../../../docs/standard/parallel-programming/task-parallel-library-tpl.md)|Provides an overview of the Task Parallel Library.|
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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)

docs/standard/parallel-programming/how-to-write-a-parallel-foreach-loop-with-thread-local-variables.md

Lines changed: 0 additions & 48 deletions
This file was deleted.

docs/standard/parallel-programming/potential-pitfalls-in-data-and-task-parallelism.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ In many cases, <xref:System.Threading.Tasks.Parallel.For%2A?displayProperty=name
1818
In certain cases a parallel loop might run slower than its sequential equivalent. The basic rule of thumb is that parallel loops that have few iterations and fast user delegates are unlikely to speedup much. However, because many factors are involved in performance, we recommend that you always measure actual results.
1919

2020
## Avoid Writing to Shared Memory Locations
21-
In sequential code, it is not uncommon to read from or write to static variables or class fields. However, whenever multiple threads are accessing such variables concurrently, there is a big potential for race conditions. Even though you can use locks to synchronize access to the variable, the cost of synchronization can hurt performance. Therefore, we recommend that you avoid, or at least limit, access to shared state in a parallel loop as much as possible. The best way to do this is to use the overloads of <xref:System.Threading.Tasks.Parallel.For%2A?displayProperty=nameWithType> and <xref:System.Threading.Tasks.Parallel.ForEach%2A?displayProperty=nameWithType> that use a <xref:System.Threading.ThreadLocal%601?displayProperty=nameWithType> variable to store thread-local state during loop execution. 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) and [How to: Write a Parallel.ForEach Loop with Thread-Local Variables](../../../docs/standard/parallel-programming/how-to-write-a-parallel-foreach-loop-with-thread-local-variables.md).
21+
In sequential code, it is not uncommon to read from or write to static variables or class fields. However, whenever multiple threads are accessing such variables concurrently, there is a big potential for race conditions. Even though you can use locks to synchronize access to the variable, the cost of synchronization can hurt performance. Therefore, we recommend that you avoid, or at least limit, access to shared state in a parallel loop as much as possible. The best way to do this is to use the overloads of <xref:System.Threading.Tasks.Parallel.For%2A?displayProperty=nameWithType> and <xref:System.Threading.Tasks.Parallel.ForEach%2A?displayProperty=nameWithType> that use a <xref:System.Threading.ThreadLocal%601?displayProperty=nameWithType> variable to store thread-local state during loop execution. 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) and [How to: Write a Parallel.ForEach Loop with Partition-Local Variables](../../../docs/standard/parallel-programming/how-to-write-a-parallel-foreach-loop-with-partition-local-variables.md).
2222

2323
## Avoid Over-Parallelization
2424
By using parallel loops, you incur the overhead costs of partitioning the source collection and synchronizing the worker threads. The benefits of parallelization are further limited by the number of processors on the computer. There is no speedup to be gained by running multiple compute-bound threads on just one processor. Therefore, you must be careful not to over-parallelize a loop.

0 commit comments

Comments
 (0)