آموزش Async و Await در سی شارپ با مثالهای عملی
آیا تا به حال هنگام کدنویسی با وضعیتهایی روبرو شدهاید که برنامه شما منتظر پاسخ یک عملیات طولانی بماند و در نتیجه عملکرد آن کاهش یابد؟ در دنیای برنامهنویسی مدرن، مدیریت همزمانی و عملیات غیرهمزمان اهمیت ویژهای دارد. اینجاست که کلیدواژههای async و await در سی شارپ وارد عمل میشوند و کارها را برای شما آسانتر میکنند. این نوشته از مجله مکتوب به آموزش async و await در سی شارپ میپردازد و شما را با زبانی ساده با این مفاهیم آشنا میکند.
Async و Await در سی شارپ چیست؟
Async و await دو کلمه کلیدی در سی شارپ هستند که برای نوشتن کدهای غیرهمزمان استفاده میشوند. کدهای غیرهمزمان به شما اجازه میدهند تا عملیات طولانی مدت مانند دسترسی به دیتابیس، درخواستهای شبکهای، و کارهای ورودی/خروجی (I/O) را بدون مسدود کردن رشته اصلی (main thread) انجام دهید.
در ادامه این بخش با رویکردی عملی به آموزش Async و Await در سی شارپ خواهیم پرداخت.
تعریف Async
کلمه کلیدی async در سی شارپ برای تعریف متدهایی استفاده میشود که عملیاتهای غیرهمزمان انجام میدهند. این متدها معمولاً یک Task یا Task<TResult> را برمیگردانند. کلمه کلیدی async به کامپایلر میگوید که این متد حاوی عملیات غیرهمزمان است.
مثال از استفاده Async:
بیایید یک متد ساده تعریف کنیم که به صورت غیرهمزمان یک پیام را با تأخیر نمایش دهد.
public async Task ShowMessageAsync() { await Task.Delay(2000); // تأخیر 2 ثانیهای Console.WriteLine("Hello, World!"); }
در این مثال، متد ShowMessageAsync با کلمه کلیدی async تعریف شده است. این متد از await استفاده میکند تا به صورت غیرهمزمان 2 ثانیه تأخیر ایجاد کند و سپس پیامی را نمایش دهد.
تعریف Await
کلمه کلیدی await در سی شارپ برای تعلیق اجرای یک متد async تا زمانی که یک Task کامل شود، استفاده میشود. این کلمه کلیدی باید در متدهای async استفاده شود و به کامپایلر میگوید که اجرای متد را تا تکمیل شدن وظیفه معلق نگه دارد.
مثال از استفاده Await
بیایید یک متد ساده تعریف کنیم که به صورت غیرهمزمان دادههایی را از یک API دریافت کند.
public async Task FetchDataAsync() { using (HttpClient client = new HttpClient()) { string data = await client.GetStringAsync("https://api.example.com/data"); return data; } }
در این مثال، متد FetchDataAsync با کلمه کلیدی async تعریف شده است. این متد از await برای معلق نگه داشتن اجرای متد تا زمان دریافت دادهها از API استفاده میکند. با استفاده از await، کد به صورت غیرهمزمان اجرا میشود و تا زمان دریافت دادهها منتظر میماند.
چرا باید از Async و Await استفاده کنیم؟
استفاده از async و await مزایای زیادی دارد. این مزایا شامل بهبود عملکرد برنامه، افزایش پاسخگویی (responsiveness)، و کاربرپسندی (user experience) بهتر میشود. با استفاده از این کلمات کلیدی، شما میتوانید برنامههایی بنویسید که بهطور همزمان چندین کار را انجام دهند بدون اینکه کاربر متوجه تأخیر یا کندی شود.
تفاوت Task و Thread در سی شارپ
یکی از سوالات متداول در مورد همزمانی در سی شارپ، تفاوت بین task و thread است. در حالی که هر دو برای اجرای همزمان کد استفاده میشوند، تفاوتهای کلیدی دارند:
Thread در سی شارپ
یک thread یک واحد اجرایی مستقل در یک برنامه است که میتواند بهطور همزمان با دیگر threads اجرا شود. با این حال، مدیریت threads پیچیده و منابع بیشتری مصرف میکند.
Task در سی شارپ
یک task نوعی انتزاع بالاتر از threads است که مدیریت همزمانی را سادهتر میکند. Tasks بهطور خودکار با thread pool یکپارچه میشوند و از منابع سیستم بهینهتر استفاده میکنند. استفاده از tasks با async و await سادهتر و خواناتر است.
چگونه از Async و Await در سی شارپ استفاده کنیم؟
استفاده از async و await در سی شارپ بسیار ساده است. بیایید با یک مثال ساده شروع کنیم.
تعریف متد Async:
برای تعریف یک متد async، کلمه کلیدی async را قبل از نوع بازگشتی متد قرار دهید:
public async Task GetDataAsync() { // عملیات طولانی مدت await Task.Delay(2000); return "Data retrieved"; }
فراخوانی متد Async
برای فراخوانی یک متد async، از کلمه کلیدی await استفاده کنید:
public async void CallGetDataAsync() { string data = await GetDataAsync(); Console.WriteLine(data); }
کاربرد Async و Await
کاربردهای async و await بسیار گسترده است. از دسترسی به دیتابیس گرفته تا درخواستهای شبکهای و عملیات I/O، همه جا میتوان از این کلمات کلیدی استفاده کرد. بیایید چند مثال کاربردی ببینیم.
پیشنهاد مطالعه: آموزش Entity Framework سی شارپ
دسترسی به دیتابیس
فرض کنید میخواهید دادههایی را از یک دیتابیس دریافت کنید. به جای مسدود کردن thread اصلی، میتوانید از async و await استفاده کنید:
public async Task<List> GetUsersAsync() { using (var context = new MyDbContext()) { return await context.Users.ToListAsync(); } }
درخواستهای شبکهای
برای ارسال درخواستهای HTTP نیز میتوانید از HttpClient با async و await استفاده کنید:
public async Task FetchDataFromApiAsync() { using (HttpClient client = new HttpClient()) { HttpResponseMessage response = await client.GetAsync("https://api.example.com/data"); return await response.Content.ReadAsStringAsync(); } }
تفاوت Async و Thread
تفاوت اصلی بین async و thread در نحوه مدیریت آنهاست. Threads منابع بیشتری مصرف میکنند و مدیریت آنها پیچیدهتر است، در حالی که async و await بهطور خودکار مدیریت همزمانی را ساده میکنند و بهینهتر هستند.
مثال جامع از استفاده همزمان async و await در سی شارپ
بیایید یک مثال جامع را بررسی کنیم که همزمان از async و await در سی شارپ استفاده میکند. در این مثال، میخواهیم دادههایی را از یک API دریافت کنیم و سپس آنها را در یک دیتابیس ذخیره کنیم. این عملیات شامل درخواست شبکهای و ذخیرهسازی در دیتابیس به صورت غیرهمزمان است.
ابتدا باید کتابخانههای لازم را نصب کنید. برای این مثال به کتابخانههای HttpClient و Entity Framework Core نیاز داریم. میتوانید از NuGet Package Manager در ویژوال استودیو استفاده کنید تا این کتابخانهها را نصب کنید:
Install-Package Microsoft.EntityFrameworkCore Install-Package Microsoft.EntityFrameworkCore.SqlServer Install-Package System.Net.Http
تعریف مدلها و کانتکست دیتابیس
ابتدا یک مدل ساده برای دیتابیس تعریف میکنیم. فرض کنید میخواهیم اطلاعات کاربران را ذخیره کنیم.
public class User { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } }
AppDbContext.cs
using Microsoft.EntityFrameworkCore; public class AppDbContext : DbContext { public DbSet Users { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=MyDatabase;Trusted_Connection=True;"); } }
ایجاد کلاس برای دریافت دادهها از API
یک کلاس ایجاد میکنیم که دادهها را از API دریافت کند.
ApiService.cs
using System.Net.Http; using System.Threading.Tasks; using Newtonsoft.Json; using System.Collections.Generic; public class ApiService { private readonly HttpClient _httpClient; public ApiService() { _httpClient = new HttpClient(); } public async Task<List> FetchUsersAsync() { var response = await _httpClient.GetStringAsync("https://api.example.com/users"); return JsonConvert.DeserializeObject<List>(response); } }
ترکیب عملیات دریافت و ذخیرهسازی
حالا یک متد ایجاد میکنیم که دادهها را از API دریافت کرده و در دیتابیس ذخیره کند.
Program.cs
using System; using System.Threading.Tasks; using System.Collections.Generic; class Program { static async Task Main(string[] args) { ApiService apiService = new ApiService(); List users = await apiService.FetchUsersAsync(); await SaveUsersToDatabaseAsync(users); Console.WriteLine("Data has been fetched and saved to the database."); } private static async Task SaveUsersToDatabaseAsync(List users) { using (var context = new AppDbContext()) { await context.Users.AddRangeAsync(users); await context.SaveChangesAsync(); } } }
شرح مثال فوق به زبان ساده:
- تعریف مدلها و کانتکست دیتابیس
ابتدا یک مدل ساده به نام User تعریف کردیم که دارای فیلدهای Id، Name و Email است. سپس یک کانتکست دیتابیس به نام AppDbContext ایجاد کردیم که از Entity Framework Core برای ارتباط با دیتابیس استفاده میکند.
- ایجاد سرویس برای دریافت دادهها از API
در کلاس ApiService، از HttpClient برای ارسال درخواست به API استفاده کردیم. متد FetchUsersAsync به صورت غیرهمزمان دادهها را از API دریافت میکند و آنها را به لیستی از کاربران (List<User>) تبدیل میکند.
- ترکیب عملیات دریافت و ذخیرهسازی
در کلاس Program، ابتدا دادهها را از API دریافت میکنیم. سپس این دادهها را به متد SaveUsersToDatabaseAsync میفرستیم تا آنها را در دیتابیس ذخیره کند. هر دو عملیات دریافت و ذخیرهسازی به صورت غیرهمزمان انجام میشوند، بنابراین برنامه مسدود نمیشود و میتواند به عملیات دیگر ادامه دهد.
با استفاده از async و await در سی شارپ، میتوانیم عملیات طولانی مدت مانند دریافت دادهها از شبکه و ذخیرهسازی در دیتابیس را به صورت غیرهمزمان انجام دهیم. این کار باعث میشود برنامه ما پاسخگوتر باشد و تجربه کاربری بهتری ارائه دهد.
آموزش کالکشن ها در سی شارپ
کالکشنها در سی شارپ شامل لیستها، آرایهها، دیکشنریها و غیره هستند که برای ذخیره و مدیریت مجموعهای از دادهها استفاده میشوند.
لیستها
لیستها یک نوع کالکشن انعطافپذیر هستند که میتوانند به راحتی تغییر اندازه دهند.
List numbers = new List { 1, 2, 3, 4 }; numbers.Add(5);
دیکشنریها
دیکشنریها یک کالکشن کلید-مقدار هستند که برای دسترسی سریع به دادهها بر اساس کلید استفاده میشوند.
Dictionary<string, string> capitals = new Dictionary<string, string> { { "France", "Paris" }, { "Germany", "Berlin" } };
Invoke در سی شارپ
متد Invoke برای اجرای کد در یک thread خاص استفاده میشود، معمولاً در برنامههای UI برای بهروزرسانی کنترلهای UI از thread اصلی استفاده میشود.
استفاده از Invoke:
this.Invoke((MethodInvoker)delegate { // کد برای بهروزرسانی UI label.Text = "Updated!"; });
Delegate در سی شارپ
Delegateها نوعی اشارهگر به متدها هستند که اجازه میدهند متدها را به صورت پویا فراخوانی کنید.
تعریف و استفاده از Delegate:
public delegate void MyDelegate(string message); public void ShowMessage(string message) { Console.WriteLine(message); } MyDelegate del = new MyDelegate(ShowMessage); del("Hello, World!");
پرسشهای متداول (FAQ)
در ادمه این بخش از آموزش async و await در سی شارپ چند سوال متدوال برای درک بهتر این مفاهیم آورده شده است:
۱. تفاوت اصلی بین async و thread چیست؟
تفاوت اصلی در نحوه مدیریت آنهاست. Threads منابع بیشتری مصرف میکنند و مدیریت آنها پیچیدهتر است، در حالی که async و await بهطور خودکار مدیریت همزمانی را ساده و بهینهتر میکنند.
۲. چگونه میتوانم از async و await برای دسترسی به دیتابیس استفاده کنم؟
با استفاده از متدهای async در Entity Framework، میتوانید به راحتی عملیات دیتابیس را به صورت غیرهمزمان انجام دهید و عملکرد برنامه را بهبود بخشید.
۳. آیا استفاده از async و await همیشه بهتر است؟
نه همیشه. برای عملیات کوتاه و ساده، استفاده از async و await ممکن است پیچیدگی غیرضروری اضافه کند. باید با توجه به نیازهای خاص پروژه از آنها استفاده کنید.
۴. آیا میتوانم از async و await در برنامههای کنسولی استفاده کنم؟
بله، async و await در همه نوع برنامههای سی شارپ قابل استفاده هستند، از جمله برنامههای کنسولی، ویندوز فرمها و ASP.NET.
۵. چه زمانی باید از Task و چه زمانی از Thread استفاده کنم؟
برای بیشتر موارد، استفاده از Task با async و await توصیه میشود زیرا مدیریت سادهتری دارد و از منابع بهینهتری استفاده میکند. Threads بیشتر در موارد خاص که نیاز به کنترل دقیقتر بر همزمانی دارید، استفاده میشود.
جمعبندی
استفاده از async و await در سی شارپ نه تنها کدهای شما را سادهتر و خواناتر میکند، بلکه به بهبود عملکرد و پاسخگویی برنامهها کمک میکند. با یادگیری مفاهیم اساسی مانند Task، Thread، Delegate و Invoke، میتوانید از پتانسیل کامل این کلمات کلیدی بهرهمند شوید و برنامههای بهینهتری بنویسید. همچنین درک شیگرایی و کالکشنها به شما کمک میکند کدهای ساختارمندتر و قابل نگهداریتری بنویسید. حالا که با این مفاهیم آشنا شدید، زمان آن رسیده که آنها را در پروژههای خود به کار بگیرید و از مزایای آنها بهرهمند شوید.
آیا آمادهاید تا به یک برنامهنویس حرفهای تبدیل شوید؟ با شرکت در دورههای آموزش سی شارپ و آموزش برنامه نویسی مکتبخونه، مهارتهای خود را به سطح بعدی ببرید! این دورهها با محتوای کاملاً کاربردی و پروژهمحور، شما را برای ورود به بازار کار آماده میکنند. از مفاهیم پایه تا مباحث پیشرفته، همه چیز به زبان ساده و قابل فهم آموزش داده میشود. همین حالا ثبتنام کنید و اولین قدم را به سوی آیندهای روشن بردارید!