[C#] Accelerating LINQ Queries with PLINQ (AsParallel)

C#’s LINQ (Language Integrated Query) is incredibly useful, but standard queries on IEnumerable<T> run sequentially on a single thread.

When dealing with large data aggregation or CPU-intensive calculations, implementing PLINQ (Parallel LINQ) allows you to effectively utilize multi-core CPU resources and dramatically improve processing speed.

This article explains how to easily parallelize existing LINQ queries using the AsParallel extension method.

目次

Implementing Parallel Queries with AsParallel

Simply adding .AsParallel() to a regular LINQ query switches the entire query to parallel execution mode (ParallelQuery<T>). You can also control the maximum number of concurrent threads using WithDegreeOfParallelism.

The following code demonstrates parallel calculation of Click-Through Rate (CTR) from multiple advertising campaign data records.

Sample Code

using System;
using System.Linq;
using System.Threading;

public class Program
{
    public static void Main()
    {
        // 1. Define Data Source (Ad Campaign Performance)
        var campaigns = new[]
        {
            new { CampaignName = "Summer Sale A", Impressions = 150000, Clicks = 4500 },
            new { CampaignName = "Winter Promo B", Impressions = 120000, Clicks = 3200 },
            new { CampaignName = "New Arrival C", Impressions = 200000, Clicks = 8500 },
            new { CampaignName = "Clearance D",   Impressions = 80000,  Clicks = 1200 },
            new { CampaignName = "Member Only E", Impressions = 50000,  Clicks = 2500 },
        };

        Console.WriteLine("--- Analysis Started ---");

        // 2. Build Parallel Query with PLINQ
        var query = campaigns
            // Convert sequential query to parallel query
            .AsParallel()
            // Specify the number of concurrent threads (Adjust based on environment/load)
            .WithDegreeOfParallelism(4)
            // Use AsOrdered() if you need to preserve order,
            // but for performance, we omit it (order is not guaranteed)
            .Select(c => new
            {
                Name = c.CampaignName,
                // Calculate Click-Through Rate (CTR)
                Ctr = (double)c.Clicks / c.Impressions * 100.0,
                // Get Thread ID to verify parallel execution
                ProcessedThreadId = Thread.CurrentThread.ManagedThreadId
            });

        // 3. Enumerate Results
        // PLINQ uses deferred execution; calculation starts when looping with foreach
        foreach (var item in query)
        {
            Console.WriteLine(
                $"Campaign: {item.Name, -15} | CTR: {item.Ctr:F2}% (Thread: {item.ProcessedThreadId})"
            );
        }
    }
}

Explanation and Technical Points

1. AsParallel Extension Method

Calling this method (found in the System.Linq namespace) partitions the data source and processes it simultaneously across multiple threads. Significant performance improvements can be expected, especially when Select or Where clauses contain complex calculations.

2. WithDegreeOfParallelism

By default, PLINQ attempts to use all available CPU cores. WithDegreeOfParallelism allows you to limit the maximum number of cores (threads) used. This is effective for preventing the process from monopolizing resources in server applications.

3. Execution Order and Side Effects

In parallel processing with PLINQ, the order of results is not guaranteed. If you need the output to match the input order, add .AsOrdered() (though this slightly reduces speed due to sorting costs).

Additionally, writing to external variables or lists from within parallel delegates (like inside Select) risks race conditions. The best practice is to design PLINQ queries to perform pure calculations without side effects.

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次