Parallel Programming in .NET

Unlock the power of multi-core processors with .NET's robust parallel programming features. This documentation explores the tools and techniques available for writing concurrent and parallel applications, significantly improving performance for computationally intensive tasks.

Introduction to Parallelism

Parallel programming allows you to divide a task into smaller sub-tasks that can be executed simultaneously on multiple processor cores. This can lead to substantial performance gains, especially in applications that involve heavy computation, data processing, or I/O-bound operations.

Task Parallel Library (TPL)

The Task Parallel Library (TPL) is the cornerstone of parallel programming in .NET. It provides a high-level abstraction for parallel operations, simplifying the management of threads and tasks.

Key TPL Concepts:

Example: Parallel.ForEach

Consider processing a large collection of items in parallel:

using System; using System.Collections.Generic; using System.Threading.Tasks; public class ParallelExample { public static void Main(string[] args) { List numbers = new List(); for (int i = 0; i < 1000; i++) { numbers.Add(i); } Parallel.ForEach(numbers, number => { // Simulate a computationally intensive operation double result = Math.Sqrt(number) * Math.Log(number); Console.WriteLine($"Processed {number} with result {result:F2} on thread {Thread.CurrentThread.ManagedThreadId}"); }); Console.WriteLine("All tasks completed."); } }

PLINQ (Parallel LINQ)

PLINQ extends Language Integrated Query (LINQ) to enable parallel execution of LINQ queries. It allows you to easily parallelize data processing operations on collections.

Key PLINQ Features:

Example: Parallel LINQ Query

using System; using System.Linq; public class PLinqExample { public static void Main(string[] args) { var data = Enumerable.Range(1, 1000000); var parallelQuery = data.AsParallel() .Where(n => n % 2 == 0) .Select(n => n * 2); // Execute the query and aggregate results long sum = parallelQuery.Sum(); Console.WriteLine($"Sum of processed numbers: {sum}"); } }

Synchronization and Thread Safety

When multiple threads access shared resources concurrently, you must implement proper synchronization mechanisms to prevent race conditions and ensure data integrity.

Common Synchronization Primitives:

Example: Using lock

using System; using System.Threading; public class Counter { private int _count = 0; private readonly object _lock = new object(); public void Increment() { lock (_lock) { _count++; } } public int GetCount() { lock (_lock) { return _count; } } } public class ThreadSafetyExample { public static void Main(string[] args) { Counter counter = new Counter(); List tasks = new List(); for (int i = 0; i < 100; i++) { tasks.Add(Task.Run(() => { for (int j = 0; j < 1000; j++) { counter.Increment(); } })); } Task.WaitAll(tasks.ToArray()); Console.WriteLine($"Final count: {counter.GetCount()}"); } }

Cancellation and Exception Handling

Properly handling cancellation requests and exceptions is crucial for robust parallel applications.

Best Practices

Explore the related topics of Asynchronous Programming and Performance Optimization for a comprehensive understanding of modern .NET development.