100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
C#

Parallel LINQ (PLINQ)

Learn how PLINQ parallelizes LINQ to Objects queries across multiple cores using AsParallel, and when parallelism actually helps.

Advanced LINQAdvanced10 min readJul 10, 2026
Analogies

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.

csharp
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

Was this page helpful?

Topics covered

#LINQStudyNotes#MicrosoftTechnologies#ParallelLINQPLINQ#Parallel#LINQ#PLINQ#AsParallel#Concurrency#StudyNotes#SkillVeris