Here are five real-world project-based exercises to master concurrency and parallel programming in C#. Each project comes with an overview, objectives, and hands-on tasks.
🚀 Project 1: High-Performance Web Scraper (Async & Parallel)
Overview
Build a multi-threaded web scraper that fetches data from multiple websites in parallel.
Objectives
✅ Use HttpClient with async/await
✅ Implement Parallel.ForEachAsync() for faster data retrieval
✅ Use ConcurrentBag to store results safely  
Implementation Steps
1️⃣ Create a list of URLs to scrape.
2️⃣ Fetch data asynchronously using HttpClient.
3️⃣ Use Parallel.ForEachAsync() for concurrent requests.
4️⃣ Store results in ConcurrentBag.  
Code Example
using System;
using System.Collections.Concurrent;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
    static async Task Main()
    {
        string[] urls = {
            "https://jsonplaceholder.typicode.com/posts/1",
            "https://jsonplaceholder.typicode.com/posts/2",
            "https://jsonplaceholder.typicode.com/posts/3"
        };
        ConcurrentBag<string> results = new ConcurrentBag<string>();
        await Parallel.ForEachAsync(urls, async (url, _) =>
        {
            using HttpClient client = new HttpClient();
            string content = await client.GetStringAsync(url);
            results.Add(content);
            Console.WriteLine($"Fetched data from {url}");
        });
        Console.WriteLine($"Total responses: {results.Count}");
    }
}
🔹 Enhancement: Store the results in a database or cache (Redis).
🚀 Project 2: Multi-Threaded File Processor
Overview
Process multiple large files concurrently.
Objectives
✅ Read multiple files asynchronously
✅ Use Parallel.ForEach() to process files in parallel
✅ Implement progress tracking  
Implementation Steps
1️⃣ Read file names from a directory.
2️⃣ Use Parallel.ForEach() to process files.
3️⃣ Store results in a thread-safe collection.  
Code Example
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading.Tasks;
class Program
{
    static void ProcessFile(string filePath)
    {
        string content = File.ReadAllText(filePath);
        Console.WriteLine($"Processed: {filePath} (Length: {content.Length})");
    }
    static void Main()
    {
        string[] files = Directory.GetFiles("C:\\Logs", "*.log");
        Parallel.ForEach(files, ProcessFile);
        Console.WriteLine("All files processed.");
    }
}
🔹 Enhancement: Save processed data in a database or cloud storage.
🚀 Project 3: Concurrent Order Processing System (Producer-Consumer)
Overview
Simulate a high-performance order processing system.
Objectives
✅ Implement the Producer-Consumer pattern
✅ Use BlockingCollection<T> for safe multi-threaded queueing
✅ Optimize performance with ThreadPool  
Implementation Steps
1️⃣ The Producer generates orders and adds them to a queue.
2️⃣ The Consumer processes orders concurrently.
3️⃣ Use BlockingCollection<T> for thread-safe queueing.  
Code Example
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
class Program
{
    static BlockingCollection<string> orderQueue = new BlockingCollection<string>();
    static void OrderProducer()
    {
        for (int i = 1; i <= 10; i++)
        {
            orderQueue.Add($"Order-{i}");
            Console.WriteLine($"Added Order-{i}");
            Thread.Sleep(100);
        }
        orderQueue.CompleteAdding();
    }
    static void OrderConsumer()
    {
        foreach (var order in orderQueue.GetConsumingEnumerable())
        {
            Console.WriteLine($"Processing {order}");
            Thread.Sleep(200);
        }
    }
    static void Main()
    {
        Task.Run(OrderProducer);
        Task.Run(OrderConsumer).Wait();
    }
}
🔹 Enhancement: Implement Kafka or RabbitMQ for real-world distributed order processing.
🚀 Project 4: Parallel Image Processing System
Overview
Apply image processing filters (resize, grayscale, blur) in parallel.
Objectives
✅ Load multiple images from a folder
✅ Use Parallel.ForEach() to apply filters
✅ Save processed images  
Implementation Steps
1️⃣ Read images from a directory.
2️⃣ Apply image filters using Parallel.ForEach().
3️⃣ Save processed images to a new folder.  
Code Example
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading.Tasks;
class Program
{
    static void ProcessImage(string filePath)
    {
        using Bitmap image = new Bitmap(filePath);
        string outputPath = Path.Combine("ProcessedImages", Path.GetFileName(filePath));
        // Convert to grayscale
        for (int x = 0; x < image.Width; x++)
        {
            for (int y = 0; y < image.Height; y++)
            {
                Color pixel = image.GetPixel(x, y);
                int gray = (pixel.R + pixel.G + pixel.B) / 3;
                image.SetPixel(x, y, Color.FromArgb(gray, gray, gray));
            }
        }
        image.Save(outputPath, ImageFormat.Jpeg);
        Console.WriteLine($"Processed: {filePath}");
    }
    static void Main()
    {
        string[] files = Directory.GetFiles("C:\\Images", "*.jpg");
        Parallel.ForEach(files, ProcessImage);
        Console.WriteLine("All images processed.");
    }
}
🔹 Enhancement: Use GPU acceleration (e.g., OpenCV) for faster processing.
🚀 Project 5: Scalable Background Job System for ASP.NET Core
Overview
Build a background task processing system using Hangfire or Worker Services.
Objectives
✅ Schedule background jobs
✅ Process jobs asynchronously
✅ Use dependency injection for services  
Implementation Steps
1️⃣ Create a Worker Service in ASP.NET Core.
2️⃣ Use Task.Run() for job execution.
3️⃣ Store job results in a database.  
Code Example
using Microsoft.Extensions.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;
public class BackgroundJob : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            Console.WriteLine($"Processing job at {DateTime.Now}");
            await Task.Delay(5000, stoppingToken);
        }
    }
}
class Program
{
    static async Task Main()
    {
        await Host.CreateDefaultBuilder()
            .ConfigureServices((_, services) => services.AddHostedService<BackgroundJob>())
            .RunConsoleAsync();
    }
}
🔹 Enhancement: Integrate Redis or RabbitMQ for distributed job queues.
🔥 Summary Table of Projects
| Project | Key Concepts | Technologies | 
|---|---|---|
| Web Scraper | Async/Await, Parallel Requests | HttpClient, ConcurrentBag | 
| File Processor | Parallel.ForEach, File I/O | Parallel Programming | 
| Order Processing | Producer-Consumer, Thread Safety | BlockingCollection, ThreadPool | 
| Image Processing | Parallel Image Manipulation | Bitmap, Parallel.ForEach | 
| Background Jobs | Scalable Task Processing | ASP.NET Worker Service | 
              
    
Top comments (2)
Great article! Concurrency and parallel programming in C# can be tricky, but you’ve explained the key concepts clearly. I especially liked your breakdown of Task.Run vs Parallel.ForEach—it’s a common point of confusion.
Keep up the good work! 🚀
Thanks bro!!