| Task Parallel Library (TPL) in C# :👈 | 👉:Functional Programming in C# |
⏳ Asynchronous Programming in C# |
⚡ Asynchronous Programming with async and await in C#
Asynchronous programming with async and await is a powerful, modern feature in C# that simplifies writing code for non-blocking operations. Introduced in C# 5.0, this model is part of the Task-based Asynchronous Pattern (TAP) and improves the responsiveness and scalability of applications—especially during I/O-bound tasks.
🚫 The Problem with Synchronous Code
In a synchronous program, a time-consuming operation (like downloading a large file or querying a database) will block the executing thread. The application becomes unresponsive until the operation completes. In a UI application, this causes the program to freeze; in a server app, it ties up valuable thread pool resources.
✅ The Solution: async and await
The async and await keywords allow you to write code that looks sequential and readable but executes in a non-blocking way.
asynckeyword: Marks a method as asynchronous. It typically returns aTaskorTask<TResult>, representing ongoing work.awaitkeyword: Suspends execution until the awaitedTaskcompletes—without blocking the thread. Control is returned to the caller, and execution resumes when the task finishes.
⚙️ How It Works: Step-by-Step Flow
- Call an async method: Execution begins on the current thread.
- Encounter await: The async method hits an
awaitexpression (usually an I/O-bound operation). - Yield control: The method pauses, returns an incomplete
Taskto its caller, and the thread is freed. - Complete the task: The awaited operation runs in the background—no threads are blocked.
- Resume execution: When the operation completes, the remainder of the method resumes from the
awaitpoint.
💻 Example: Downloading a Web Page Asynchronously
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
public class AsyncExample
{
// The 'async' keyword allows 'await' to be used in this method.
public static async Task DownloadPageAsync()
{
Console.WriteLine("Starting download... (Thread ID: " + Thread.CurrentThread.ManagedThreadId + ")");
using var client = new HttpClient();
// The 'await' keyword suspends execution here and frees the thread.
string content = await client.GetStringAsync("http://www.example.com");
// Execution resumes here after download completes.
Console.WriteLine("\nDownload complete! (Thread ID: " + Thread.CurrentThread.ManagedThreadId + ")");
Console.WriteLine($"Downloaded content length: {content.Length}");
}
public static async Task Main()
{
Task downloadTask = DownloadPageAsync();
Console.WriteLine("Main method is doing other work... (Thread ID: " + Thread.CurrentThread.ManagedThreadId + ")");
// Simulate concurrent work
for (int i = 0; i < 5; i++)
{
Console.Write(".");
await Task.Delay(200);
}
// Wait for the download to complete
await downloadTask;
Console.WriteLine("\nMain method finished.");
}
}
⏳ Asynchronous Programming with async/await in C#
Asynchronous programming allows your application to perform tasks like I/O operations, network calls, or file access without blocking the main thread. In C#, this is achieved using the async and await keywords.
📌 Version Introduced
The async/await pattern was introduced in C# 5.0 with the release of .NET Framework 4.5.
🔧 How It Works
asyncmarks a method as asynchronous.awaitpauses execution until the awaited task completes.- The method returns a
TaskorTask<T>.
🧪 Example: Async Web Request
using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program {
static async Task Main() {
Console.WriteLine("Starting download...");
HttpClient client = new HttpClient();
string html = await client.GetStringAsync("https://example.com");
Console.WriteLine($"Downloaded {html.Length} characters.");
}
}
✅ Best Practices
- Use
asyncfor I/O-bound operations (e.g., file, network). - Avoid
.Resultor.Wait()—they block threads. - Use
ConfigureAwait(false)in library code to avoid deadlocks. - Use
Task.WhenAll()to run multiple tasks concurrently. - Handle exceptions with
try-catchinside async methods.
📌 When to Use
- To keep UI responsive in desktop/mobile apps.
- For web APIs handling multiple requests.
- When performing long-running I/O operations.
🚫 When Not to Use
- For CPU-bound tasks—use
Task.Run()orParallel. - In performance-critical loops—async adds overhead.
- For short, synchronous logic—no need for async.
⚠️ Precautions
- Don’t mix async and blocking code—it can cause deadlocks.
- Use cancellation tokens to cancel async operations gracefully.
- Be cautious with shared resources—use locks if needed.
🎯 Advantages
- Responsiveness: Keeps UI and services fluid.
- Scalability: Handles many tasks with fewer threads.
- Readability: Cleaner than callbacks or event-based models.
- Efficiency: Frees up threads during I/O waits.
📝 Conclusion
Asynchronous programming with async and await is essential for building modern, responsive, and scalable applications in C#. It simplifies complex workflows and helps you write clean, maintainable code.
🧠 Best Practices
- Async all the way: If a method calls an async method, it should also be async and use
await. - Use
async Task, notasync void: Except for event handlers, always returnTaskorTask<TResult>. - Avoid blocking calls: Don’t use
.Resultor.Wait()in async code—they can cause deadlocks. - Name async methods with “Async”: Follow convention (e.g.,
DownloadPageAsync). - Use
ConfigureAwait(false)in libraries: Improves performance and avoids capturing synchronization context.
🏁 Summary
The async/await model allows developers to write clear, maintainable, and responsive code for asynchronous operations. It keeps apps fast and responsive, avoids blocking threads, and integrates seamlessly with the Task Parallel Library (TPL). When used correctly, it makes asynchronous programming in C# both elegant and efficient.
| Task Parallel Library (TPL) in C# :👈 | 👉:Functional Programming in C# |