- Parallel LINQ can be used on objects to potentially turn a sequential query into a parallel one.
- Extension methods for using PLINQ are defined in the System.Linq.ParallelEnumerable class.
public List<string> ParallelEncrypt(List<string> data) => data.AsParallel().Select((item) => Encrypt(item)).ToList();
- Using the standard query operator
AsParallel()
, the runtime begins executing over the items within the data collection and execute an action in parallel.
- The result is a completion time that gets noticeably shorter than the synchronous alternative over a significantly sized set when there are multiple processors.
- Invoking the parallel version simply involves a call to the
IEnumerable<T>.AsParallel()
extension method.
- Furthermore, the result of calling a parallel standard query operator is a parallel enumerator, usually
ParallelQuery<T>
, which means that further operations on the result of a PLINQ query will be performed in parallel.
- PLINQ exceptions are accessible via the
InnerExceptions
property of the AggregateException
.
- Therefore, wrapping a PLINQ query in a try/catch block with the exception type of
System.AggregateException
will successfully handle any exceptions within each iteration that were unhandled.
- You can limit the amount of parallelism that is used with the
WithDegreeOfParallelism
method.
- You pass that method an integer that represents the number of processors that you want to use.
- Normally, PLINQ uses all processors (up to 64).
- Parallel processing does not guarantee any particular order.
- The results of the parallel code vary depending on the amount of CPUs that are available.
AsOrdered
specifies that PLINQ should preserve the ordering of the source sequence for the rest of the query, or until the ordering is changed.
- The query is still processed in parallel, but the results are buffered and sorted.
var numbers = Enumerable.Range(1, 20)
.AsParallel()
.AsOrdered()
.Where(x => x % 5 == 0);
foreach (var number in numbers)
Console.WriteLine(number);
- If you have a complex query that can benefit from parallel processing but also has some parts that should be done sequentially, use the
AsSequential
.
- It specifies that the rest of the query should be run sequentially, as a non-parallel LINQ query.
- One scenario where this is required is to preserve the ordering of your query.
var parallelResult = Enumerable.Range(1, 20)
.AsParallel()
.Where(x => x % 2 == 0)
.AsSequential();
foreach (var number in parallelResult.Take(5))
Console.WriteLine(number);
- Use the
ForAll
operator to iterate over a collection when the iteration can also be done in a parallel way.
- It is a multithreaded enumeration method that enables results to be processed in parallel without first merging back to the consumer thread.
- In contrast to
foreach
, ForAll
does not need all results before it starts executing.
Enumerable.Range(1, 20)
.AsParallel()
.Where(x => x % 2 == 0)
.ForAll(x => Console.WriteLine(x));
Canceling a PLINQ Query
- Like the parallel loops, canceled PLINQ queries will throw a
System.OperationCanceledException
.