What PLINQ Is
Parallel LINQ, or PLINQ, is a parallel implementation of LINQ to Objects that spreads query execution across multiple CPU cores using the Task Parallel Library under the hood. You opt in by calling .AsParallel() on any IEnumerable<T> source, after which subsequent operators like Where, Select, and Aggregate are executed by a ParallelQuery<T> that partitions the source data, processes chunks concurrently on separate threads, and merges the results back together, potentially finishing much faster than a sequential LINQ query on CPU-bound, data-parallel workloads.
Cricket analogy: PLINQ is like a groundstaff crew of ten workers mowing a cricket outfield simultaneously, each covering their own section, instead of one groundsman mowing the whole outfield alone; the job finishes far faster when the work is genuinely divisible.
Using AsParallel and Controlling Execution
Calling .AsParallel() converts the source into a ParallelQuery<T>; you can further tune behavior with .WithDegreeOfParallelism(n) to cap the number of threads used, .AsOrdered() to preserve source ordering in the output (at some performance cost), and .WithExecutionMode(ParallelExecutionMode.ForceParallelism) to override PLINQ's heuristic that might otherwise decide a query is too cheap to parallelize. For queries that should fall back to sequential execution partway through, .AsSequential() reverts to standard LINQ to Objects semantics for the remaining operators in the chain.
Cricket analogy: WithDegreeOfParallelism is like a captain deciding to use exactly four fielders for a specific drill instead of the full eleven, deliberately capping resources rather than always deploying every player available.
var numbers = Enumerable.Range(1, 10_000_000);
// Sequential LINQ
var sequentialResult = numbers.Where(IsPrime).Count();
// PLINQ: parallelized across available cores
var parallelResult = numbers
.AsParallel()
.WithDegreeOfParallelism(Environment.ProcessorCount)
.Where(IsPrime)
.Count();
// Preserve order when it matters, at a performance cost
var orderedTop10 = numbers
.AsParallel()
.AsOrdered()
.Where(IsPrime)
.Take(10)
.ToList();
static bool IsPrime(int n)
{
if (n < 2) return false;
for (int i = 2; i * i <= n; i++)
if (n % i == 0) return false;
return true;
}When Parallelism Helps and When It Hurts
PLINQ gives the biggest wins on CPU-bound, computationally expensive per-element work over reasonably large collections, such as the prime-checking example above. For small collections, cheap per-element operations (like a simple property comparison), or I/O-bound work, the overhead of partitioning data, coordinating threads, and merging results usually outweighs any benefit, and a sequential LINQ query — or async I/O instead of PLINQ for I/O-bound work — will be faster. PLINQ also assumes the delegate you pass is thread-safe and side-effect-free; mutating shared state inside a Select or Where lambda under PLINQ causes race conditions.
Cricket analogy: This is like deploying a full ten-fielder rotation drill just to field a single, easy return catch — the coordination overhead of organizing everyone dwarfs the trivial task, whereas that same rotation makes sense for a genuinely demanding fielding drill covering the whole ground.
PLINQ does not guarantee thread safety for the delegates you supply. If a Select or Where lambda mutates a shared List<T>, increments a shared counter, or writes to a non-thread-safe collection, you will get race conditions and corrupted results. Either avoid shared mutable state entirely inside PLINQ delegates, or use thread-safe constructs like ConcurrentBag<T> or Interlocked operations if shared state is unavoidable.
- PLINQ parallelizes LINQ to Objects queries across CPU cores by calling .AsParallel() on an IEnumerable<T>.
- WithDegreeOfParallelism controls how many threads are used for a query.
- AsOrdered preserves source ordering in the results, at some performance cost.
- WithExecutionMode(ForceParallelism) overrides PLINQ's own heuristic about whether to parallelize.
- PLINQ is best suited to CPU-bound, computationally expensive per-element work over large collections.
- For small collections or cheap operations, sequential LINQ is often faster due to coordination overhead.
- Delegates passed to PLINQ operators must be thread-safe; mutating shared state causes race conditions.
Practice what you learned
1. What method converts a standard LINQ to Objects query into a PLINQ query?
2. Which PLINQ method preserves the original source ordering in the output, at a performance cost?
3. For which type of workload does PLINQ typically provide the biggest performance benefit?
4. What is a key requirement for delegates passed into PLINQ operators like Select or Where?
5. What does .AsSequential() do in a PLINQ query chain?
Was this page helpful?
You May Also Like
Lambda Expressions in LINQ
Understand how lambda expressions power LINQ's filtering, projection, and aggregation operators, and how they differ from anonymous methods and expression trees.
Custom LINQ Extension Methods
Learn how to write your own LINQ-style extension methods on IEnumerable<T>, including deferred execution with yield return and chaining conventions.
Expression Trees Explained
Learn what expression trees are, how the compiler builds them from lambdas, and how providers like EF Core walk them to generate SQL.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesMFC (Microsoft Foundation Classes) Study Notes
C++ · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics