হ্যালো হাসিব! আজকের লেকচারটি তোমার অ্যাপ্লিকেশনের পারফরম্যান্স এবং স্কেলেবিলিটির জন্য খুবই ক্রিটিক্যাল। আমরা .NET-এর সবচেয়ে পাওয়ারফুল ফিচারগুলোর একটি—Asynchronous Programming (async & await)—নিয়ে কথা বলবো।
বিশেষ করে ডাটাবেসের সাথে কাজ করার সময় (Entity Framework Core), Synchronous (সিঙ্ক্রোনাস) কোড লিখলে তোমার সার্ভার খুব সহজেই ব্লক হয়ে যেতে পারে। চলো লেকচারটির একটি কুইক সামারি এবং বিস্তারিত পোস্টমর্টেম করে ফেলি।
📝 Lecture Summary at a Glance
- Why Async? ডাটাবেস থেকে ডাটা আনা বা ফাইলে কিছু লেখার মতো কাজগুলো (I/O Bound) অনেক সময় নেয়। Async ব্যবহার করলে এই সময়টাতে সার্ভারের থ্রেড (Thread) বসে না থেকে অন্য ইউজারের রিকোয়েস্ট হ্যান্ডেল করতে পারে। এতে সার্ভারের পারফরম্যান্স এবং ক্যাপাসিটি বহুগুণ বেড়ে যায়।
- Task Keyword: C#-এ অ্যাসিংক্রোনাস মেথডের রিটার্ন টাইপ সবসময়
TaskবাTask<T>হয় (যাSystem.Threading.Tasksনেমস্পেস থেকে আসে)। - Entity Framework Async Methods: EF Core-এর সবগুলো অপারেশন (যেমন:
ToList,FirstOrDefault,SaveChanges) এর একটি করেAsyncভার্সন আছে (ToListAsync,FirstOrDefaultAsync,SaveChangesAsync)। - The Rule of Await: যেকোনো
Asyncমেথড কল করার আগে অবশ্যইawaitবসাতে হবে। আর কোনো মেথডের ভেতরেawaitব্যবহার করতে হলে সেই মেথডের সিগনেচারেasyncথাকতে হবে।
🧠 Comprehensive Breakdown & Deep Dive
১. Async/Await কী এবং কেন এটি ব্যবহার করবে? [Importance: 10/10]
-
The “Why”: ধরো তুমি একটি রেস্টুরেন্টের ওয়েটার (সার্ভার থ্রেড)। একজন কাস্টমার (রিকোয়েস্ট) পিৎজা অর্ডার করলো, যা বানাতে (ডাটাবেস অপারেশন) ১৫ মিনিট লাগবে।
-
Synchronous (খারাপ): তুমি ওই ১৫ মিনিট কিচেনের সামনে দাঁড়িয়ে থাকবে। অন্য কোনো কাস্টমার এলে তুমি অর্ডার নিতে পারবে না।
-
Asynchronous (স্মার্ট): তুমি কিচেনে অর্ডারটা দিয়ে (await) অন্য কাস্টমারের কাছে চলে যাবে। পিৎজা রেডি হলে কিচেন তোমাকে ডাকবে, তুমি তখন খাবারটা সার্ভ করবে।
-
Backend Perspective: তোমার “Chatrabash” প্রজেক্টে যদি ১০০ জন ইউজার একসাথে ডাটাবেসে রিকোয়েস্ট পাঠায়, আর তুমি যদি
asyncব্যবহার না করো, তবে তোমার সার্ভারের সবগুলো থ্রেড ব্লক হয়ে যাবে এবং ওয়েবসাইট ক্র্যাশ বা স্লো হয়ে যাবে।
২. Service Interface (Contract) আপডেট করা [Importance: 9/10]
- The “Why”: যেহেতু আমরা মেথডগুলোকে অ্যাসিংক্রোনাস বানাচ্ছি, তাই তাদের রিটার্ন টাইপ পরিবর্তন করতে হবে। ইন্টারফেসে (যেমন
IPersonsService) যদি মেথড আগেPersonResponseরিটার্ন করতো, এখন তাকে একটি “প্রমিস” বাTask<PersonResponse>রিটার্ন করতে হবে।
💻 Code Implementation:
using System.Threading.Tasks;
public interface ICountriesService
{
// ❌ Old Synchronous Signature:
// CountryResponse AddCountry(CountryAddRequest request);
// ✅ New Asynchronous Signature:
Task<CountryResponse> AddCountry(CountryAddRequest request);
Task<List<CountryResponse>> GetAllCountries();
Task<CountryResponse?> GetCountryByCountryId(Guid? countryId);
}
৩. Service Implementation আপডেট করা [Importance: 10/10]
- The “Why”: ইন্টারফেসের সাথে মিলিয়ে মূল সার্ভিস ক্লাসের মেথডগুলোতেও
asyncএবংTaskবসাতে হবে। এরপর EF Core-এর যেসব মেথড সরাসরি ডাটাবেসে হিট করে (I/O operations), সেগুলোকেAsyncভার্সনে কনভার্ট করেawaitকরতে হবে।
💻 Code Implementation (The Refactoring):
public class CountriesService : ICountriesService
{
private readonly PersonsDbContext _db;
// মেথডের সিগনেচারে async যুক্ত করা হলো
public async Task<CountryResponse> AddCountry(CountryAddRequest request)
{
Country country = request.ToCountry();
country.CountryId = Guid.NewGuid();
// ❌ _db.Countries.Add(country); (Add এর Async দরকার নেই, কারণ এটি শুধু মেমোরিতে স্টেট চেঞ্জ করে)
_db.Countries.Add(country);
// ✅ DataBase হিট হচ্ছে, তাই SaveChangesAsync এবং await ব্যবহার করা হলো
await _db.SaveChangesAsync();
return country.ToCountryResponse();
}
public async Task<List<CountryResponse>> GetAllCountries()
{
// ❌ _db.Countries.ToList();
// ✅ ToListAsync() ব্যবহার করে ডাটাবেস থেকে অ্যাসিংক্রোনাসলি ডাটা আনা হচ্ছে
var countries = await _db.Countries.ToListAsync();
return countries.Select(c => c.ToCountryResponse()).ToList();
}
}
৪. Where NOT to use Async/Await [Importance: 8/10]
- The “Why”: তুমি যদি এমন কোনো কাজ করো যা ডাটাবেস বা এক্সটার্নাল ফাইলের সাথে যুক্ত নয় (যেমন: ইন-মেমোরি লিস্টকে সর্ট করা বা ফিল্টার করা, অথবা
Selectদিয়ে ম্যাপ করা), সেখানে খামোখাasyncব্যবহার করবে না। এটি শুধুমাত্র I/O Bound কাজের জন্য। লেকচারার এটি মেনশন করেছেন।
🚀 Best Practices for Asynchronous Programming in .NET
হাসিব, Async প্রোগ্রামিংয়ের ক্ষেত্রে নিচের নিয়মগুলো সবসময় মেনে চলবে:
১. Async All The Way Down:
তুমি যদি কোনো মেথডকে async বানাও, তবে তার পেছনের চেইনের সবগুলো মেথডকেই (Controller থেকে শুরু করে Repository পর্যন্ত) async বানাতে হবে। মাঝে কোথাও সিঙ্ক্রোনাস কোড দিয়ে ব্লক করলে ডেডলক (Deadlock) হওয়ার সম্ভাবনা থাকে। (পরের লেকচারে লেকচারার Controller-এ এই কাজটাই করবেন)।
২. Avoid async void:
কখনোই কোনো মেথডের রিটার্ন টাইপ async void দেবে না (শুধুমাত্র Event Handler ছাড়া)। সবসময় async Task ব্যবহার করবে। void দিলে তুমি মেথডটির এক্সেপশন (Error) ঠিকমতো ধরতে বা হ্যান্ডেল করতে পারবে না।
৩. Never use .Result or .Wait():
অ্যাসিংক্রোনাস মেথড থেকে ডাটা বের করার জন্য ভুল করেও .Result বা .Wait() কল করবে না। এটি সার্ভার থ্রেডকে ব্লক করে দেয়। সবসময় await ব্যবহার করবে।
লেকচারার বলেছেন যে মেথড সিগনেচার চেঞ্জ করার কারণে Controller এবং Test প্রজেক্টে অনেক বিল্ড এরর (Build Errors) আসবে, যা তিনি দ্বিতীয় পার্টে সলভ করবেন। তুমি রেডি হলে সেই পরের অংশের ট্রান্সক্রিপ্টটি দিতে পারো!