async programming
C#
Task\`\`\`\``<T>`\`\`\`\`
await vs Result
.NET concurrency

What is the difference between await TaskT and TaskT.Result?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

await task and task.Result can both eventually give you a T, but they do it in very different ways. await is asynchronous and non-blocking from the caller's point of view, while .Result is synchronous and blocks the current thread until the task finishes.

That difference affects responsiveness, scalability, exception behavior, and deadlock risk. In modern C#, await is usually the correct choice unless you are forced to stay in a synchronous API boundary.

await Does Not Block the Thread

When you await a Task<T>, the method yields control until the task completes. The method resumes later and gives you the result value.

csharp
1using System.Net.Http;
2
3public async Task<string> LoadPageAsync(HttpClient client)
4{
5    HttpResponseMessage response = await client.GetAsync("https://example.com");
6    response.EnsureSuccessStatusCode();
7    return await response.Content.ReadAsStringAsync();
8}

Important details:

  • 'await does not start the task by itself; it waits for an existing task'
  • the current method is suspended, but the thread is free to do other work
  • exceptions are rethrown in a natural way, so normal try and catch works cleanly

This is why await is the idiomatic choice for I/O-bound work in ASP.NET, desktop apps, and most modern .NET code.

.Result Blocks the Current Thread

Task<T>.Result waits synchronously for the task to finish and then returns the value.

csharp
1using System.Net.Http;
2
3public string LoadPage(HttpClient client)
4{
5    HttpResponseMessage response = client.GetAsync("https://example.com").Result;
6    response.EnsureSuccessStatusCode();
7    return response.Content.ReadAsStringAsync().Result;
8}

This code can work, but it blocks the caller while the network request is in flight. On a UI thread, that can freeze the interface. On a server, it can waste thread pool threads and reduce throughput.

The biggest practical issue is that blocking on async work often creates avoidable problems even when the code "works on my machine."

Deadlocks and Context Problems

Historically, .Result has been notorious for causing deadlocks in contexts that capture a synchronization context, such as older ASP.NET, WinForms, and WPF.

The pattern looks like this:

  1. async work captures the current context
  2. .Result blocks that same thread
  3. the continuation wants to resume on the blocked context
  4. nothing can proceed

Modern ASP.NET Core is less prone to this specific deadlock pattern, but blocking is still a poor tradeoff because it harms scalability and complicates exception handling.

Exception Behavior Is Different

Another important difference is how exceptions surface:

  • 'await rethrows the original exception in a natural way'
  • '.Result wraps failures in AggregateException'

Example:

csharp
1try
2{
3    var value = await GetValueAsync();
4}
5catch (InvalidOperationException ex)
6{
7    Console.WriteLine(ex.Message);
8}

Versus:

csharp
1try
2{
3    var value = GetValueAsync().Result;
4}
5catch (AggregateException ex)
6{
7    Console.WriteLine(ex.InnerException?.Message);
8}

That is one more reason await is usually easier to reason about.

What to Do at a Synchronous Boundary

Sometimes you are forced to return a synchronous result because of an older interface or library contract. Even then, the best long-term fix is usually "async all the way down."

If you truly must block, many developers prefer GetAwaiter().GetResult() because it avoids the AggregateException wrapper. But that still blocks, so it should be treated as an escape hatch, not normal async style.

Common Pitfalls

  • Assuming await creates a new thread. It usually does not; it coordinates asynchronous completion.
  • Using .Result in UI code and freezing the app.
  • Mixing sync and async code paths until deadlocks or thread starvation appear.
  • Forgetting that .Result wraps exceptions differently.
  • Believing .Result is faster because it looks simpler. Blocking usually hurts overall performance and responsiveness.

Summary

  • 'await task waits asynchronously and does not block the current thread.'
  • 'task.Result waits synchronously and blocks the current thread.'
  • 'await is safer for responsiveness, scalability, and exception handling.'
  • '.Result can cause deadlocks or throughput problems when used on async operations.'
  • Prefer await in modern C# and use blocking only at unavoidable synchronous boundaries.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.