Skip to content

Difference Between Synchronous and Asynchronous Programming

We have now seen both styles of programming. In this lesson we put them side by side so the difference is crystal clear.

A phone call is synchronous: while you are on the call, you are busy and must wait for the other person to answer. A WhatsApp message is asynchronous: you send it, put your phone away and do other things. When the reply comes, you read it.

Comparison table

PointSynchronousAsynchronous
How tasks runOne after another, in a fixed orderA task is started, and the program continues without waiting for it
WaitingThe thread waits (is blocked) until the task finishesThe thread is released while waiting and can do other work
Total time for independent tasksSum of all task timesClose to the time of the longest task
User interfaceFreezes during long workStays responsive
Web serversEach waiting request holds a thread, so fewer users can be servedThreads are returned to the pool while waiting, so more users can be served
Code style in C#Normal methods returning void, int, string...async methods returning Task or Task<T>, called with await
Method namesReadAllText, ExecuteReader, SaveChangesReadAllTextAsync, ExecuteReaderAsync, SaveChangesAsync
Ease of understandingVery simpleSimple with async/await, but you must learn a few rules
DebuggingEasy, the call stack is straightforwardA little harder, code resumes later and maybe on another thread
Best forQuick work and pure calculationsWork that waits: database, files, network, web APIs

Side by side: reading a file

// Synchronous: the thread waits until the whole file is read
static void ShowFileSize()
{
    string text = File.ReadAllText("orders.txt");
    Console.WriteLine($"Characters: {text.Length}");
}

// Asynchronous: the thread is free while the disk reads the file
static async Task ShowFileSizeAsync()
{
    string text = await File.ReadAllTextAsync("orders.txt");
    Console.WriteLine($"Characters: {text.Length}");
}

Both methods produce the same result. The difference is what the thread does while the disk is working. In the first one it sits idle. In the second one it goes back and can do other work.

Side by side: reading from SQL Server

// Synchronous
public List<string> GetCustomerNames()
{
    var names = new List<string>();
    using var connection = new SqlConnection(connectionString);
    connection.Open();
    using var command = new SqlCommand("SELECT Name FROM Customers", connection);
    using var reader = command.ExecuteReader();
    while (reader.Read())
    {
        names.Add(reader.GetString(0));
    }
    return names;
}

// Asynchronous
public async Task<List<string>> GetCustomerNamesAsync()
{
    var names = new List<string>();
    using var connection = new SqlConnection(connectionString);
    await connection.OpenAsync();
    using var command = new SqlCommand("SELECT Name FROM Customers", connection);
    using var reader = await command.ExecuteReaderAsync();
    while (await reader.ReadAsync())
    {
        names.Add(reader.GetString(0));
    }
    return names;
}

See how similar they look. With async and await, asynchronous code reads almost exactly like synchronous code. That is the main reason these keywords exist.

Side by side: timing

// Synchronous: about 5 seconds
Thread.Sleep(2000);
Thread.Sleep(3000);

// Asynchronous, one after another: still about 5 seconds
await Task.Delay(2000);
await Task.Delay(3000);

// Asynchronous, at the same time: about 3 seconds
await Task.WhenAll(Task.Delay(2000), Task.Delay(3000));

Writing await on each line one after another does not make tasks overlap. It only frees the thread while waiting. To make independent tasks overlap, start them first and then await them together, for example with Task.WhenAll.

Which one should I choose?

  • If the code waits on a database, file, network or API, use asynchronous code.
  • If the code only calculates and finishes quickly, use synchronous code.
  • In ASP.NET Core, controller actions that talk to a database or another service should be asynchronous.

Summary

  • Synchronous: do one thing, wait for it, then do the next thing.
  • Asynchronous: start a thing, do other work, and come back when it is done.
  • Synchronous blocks the thread while waiting; asynchronous releases it.
  • Async methods return Task / Task<T> and their names end with Async.
  • To overlap work, start the tasks first, then await them.