Skip to main content
๐Ÿ“œ WAYPOINT LESSON

PLINQ: parallel query, real costs

โญโญโญ advancedโณ 15 min read๐Ÿ“ Lesson 203 of 265

AsParallel, ordering, merging, degree of parallelism โ€” and the workloads where PLINQ loses to LINQ.

PLINQ: parallel query, real costs

.AsParallel() turns a LINQ query into a parallel pipeline; PLINQ partitions the source, runs operators concurrently, and merges results:

var heavy = urls.AsParallel()
                .Select(ParseAndScore)      // CPU-bound, expensive per item
                .Where(s => s > threshold)
                .ToArray();

The merge behavior is the first surprise: PLINQ reorders by default. It buffers results to yield them faster, sacrificing order for throughput. .AsOrdered() restores source order at a real buffering cost โ€” pay it only when order is part of the answer.

What PLINQ is good at: CPU-bound element-wise work over large inputs (Select with expensive transforms), Aggregate with seeded overloads. What it is bad at:

  • Tiny per-item work โ€” partition overhead eats the win (the same rule as Parallel.For).
  • Order-dependent operators โ€” Take, First, Skip need sequence semantics that fight partitioning.
  • Side-effecting lambdas โ€” they now run on many threads; your closure had better be thread-safe.
  • I/O-bound work โ€” PLINQ parallelizes THREADS, not waiting. Awaiting a network call inside PLINQ blocks pool threads. That job belongs to Task.WhenAll/async streams.

WithDegreeOfParallelism(n) caps the worker count โ€” essential when several PLINQ queries share a process, or when the box is shared. AsSequential() drops back to sequential mid-query when a later operator cannot be parallelized.