common problems with parallel loops and their solutions - C#. NET

Take a look at the following sections for the common problems with parallel loops and their solutions.

Synchronization in Loop Bodies
A synchronization primitive is used to coordinate access to a shared variable, typically a result. Performance is significantly reduced because the tasks performing the loop body must wait to acquire the primitive on each loop body iteration.

Use TLS instead of a synchronization primitive

The following example uses the lock keyword to synchronize access to a double value used to keep a running total shared between iterations of the loop body:

Loop Body Data Races
A variation of the previous problem is to share data in the loop body without synchronization. This doesn’t have the performance impact of using synchronization but creates a data race instead.

Use TLS as shown.

The following example shows a data race where an unexpected result is generated by sharing a data value across iterations of the loop body.

Using Standard Collections
Results generated from a parallel loop body are placed in a normal collection, as opposed to one from the System.Collections.Concurrent namespace. These collections are liable to suffer from data races when used in parallel programming and will either throw exceptions or contain unexpected results.

Always use collections from the System.Collections.Concurrent namespace.

The following example illustrates this problem by using a loop body that adds items to an instance of System.Collections.Generic.List. Running the example will either result in an unexpected number of items in the result collection or an exception when the state of the list is modified by two Tasks at once.

Using Changing Data
A parallel loop is used to consume data that is still being produced or modified. Unexpected results will occur because not all of the data items or unexpected values will be processed.

Avoid working with data that is being changed elsewhere. If you need to process data as it is being produced, you must implement a custom partitioner that will continue to push data to the parallel loop Tasks as it becomes available.

The following example shows a Task that periodically adds an item to a List. A Parallel.ForEach loop processes the same List. However, because the contents are partitioned when the parallel loop starts, any items that the Task adds after that point are not processed.

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd Protection Status

C#. NET Topics