C#  

Synchronous vs Asynchronous Programming with CPU-bound & I/O-bound Examples

1๏ธโƒฃ Introduction

When writing software, especially in .NET or any modern language, you’ll often hear the terms synchronous and asynchronous.

Understanding these concepts — along with CPU-bound and I/O-bound work — will help you write faster, more responsive applications.

2๏ธโƒฃ Synchronous Programming

Definition

In synchronous programming, tasks are executed one after another.

The next task won’t start until the previous one is completely finished.

Real-life analogy

Imagine you are at a restaurant.

The waiter takes your order, goes to the kitchen, waits until your food is ready, serves you, and only then takes the next customer’s order.

using System;
using System.Threading;

class Program
{
    static void Main()
    {
        Console.WriteLine("Task 1 start");
        Task1(); // Wait until complete
        Console.WriteLine("Task 2 start");
        Task2(); // Wait until complete
        Console.WriteLine("All done");
    }

    static void Task1()
    {
        Thread.Sleep(3000); // Simulate 3 sec work
        Console.WriteLine("Task 1 complete");
    }

    static void Task2()
    {
        Thread.Sleep(2000); // Simulate 2 sec work
        Console.WriteLine("Task 2 complete");
    }
}

โณ Total time: 5 seconds (3s + 2s)

3๏ธโƒฃ Asynchronous Programming

Definition

In asynchronous programming, you can start multiple tasks and let them run independently.

The program doesn’t wait for a task to finish before moving on — unless explicitly told to.

Real-life analogy

In the same restaurant, the waiter takes your order and sends it to the kitchen, then takes orders from other customers while your food is cooking.

using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        Console.WriteLine("Task 1 start");
        var task1 = Task1(); // Start without waiting
        Console.WriteLine("Task 2 start");
        var task2 = Task2(); // Start without waiting

        await Task.WhenAll(task1, task2); // Wait for both to finish
        Console.WriteLine("All done");
    }

    static async Task Task1()
    {
        await Task.Delay(3000); // Simulate 3 sec work
        Console.WriteLine("Task 1 complete");
    }

    static async Task Task2()
    {
        await Task.Delay(2000); // Simulate 2 sec work
        Console.WriteLine("Task 2 complete");
    }
}

โณ Total time: ~3 seconds (runs in parallel)

4๏ธโƒฃ CPU-bound vs I/O-bound

CPU-bound

  • Definition: CPU is fully busy doing calculations (no waiting).
  • Examples: Image processing, data encryption, prime number calculation.
  • Best optimization: Multi-threading or parallel processing.

C# CPU-bound Example

static void CalculatePrimeNumbers()
{
    for (int i = 2; i < 500000; i++)
    {
        bool isPrime = true;
        for (int j = 2; j * j <= i; j++)
        {
            if (i % j == 0) { isPrime = false; break; }
        }
    }
}

I/O-bound

  • Definition: Waiting for Input/Output (disk, network, database).
  • Examples: API calls, file read/write, database queries.
  • Best optimization: Async/await.

C# I/O-bound Example

using System.Net.Http;

static async Task FetchDataAsync()
{
    using var client = new HttpClient();
    string result = await client.GetStringAsync("https://jsonplaceholder.typicode.com/posts/1");
    Console.WriteLine(result);
}

5๏ธโƒฃ Visual Timeline

Time โ†’
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

CPU-bound (single thread):
[######## CPU Busy ########][######## CPU Busy ########]

I/O-bound (sync):
[Send Request][Idle........waiting........][Process Data]

I/O-bound (async):
[Send Request] โ†’ (CPU เฆ…เฆจเงเฆฏ เฆ•เฆพเฆœ เฆ•เฆฐเฆ›เง‡) โ†’ [Process Data]

6๏ธโƒฃ Summary Table

Feature Synchronous Asynchronous
Execution order One by one Overlapping tasks
Performance Slower for I/O Faster for I/O
CPU usage Idle during wait More efficient
Complexity Simple Slightly harder
Use case Simple scripts UI apps, servers

โœ… Key takeaway

  • If your work is I/O-bound → use async/await.
  • If your work is CPU-bound → use parallel processing or multi-threading.