اجرای همزمان و غیرهمزمان دستورات در سی شارپ اهمیت بسیار زیادی دارند، زیرا گاهی نیاز است تا چند کار به صورت همزمان انجام بشود.
اجرای عملیات همزمان یعنی اینکه بتوانیم چندین کار را به صورت همزمان باهم اجرا کنیم. در سیستم اجرای دستورات بیشتر زبان های برنامه نویسی به طور معمول دستورات به صورت غیرهمزمان یا sync اجرا می شوند، برای مثال:
فرض کنید قرار است چند بسته پستی را به چند محل مختلف انتقال دهید:
📌در روش غیرهمزمان، بسته ها باید یکی یکی و پشت سرهم انتقال داده شوند، در واقع بسته های بعدی باید منتظر بمانند تا بسته های قبلی به محل مورد نظر خود رسیده باشند، این روش باعث اجرای کند فرآیند انتقال بسته ها می شود، در واقع زمان بسیار زیادی نیاز است تا کلیه بسته ها را بتوان ارسال کرد.
📌اما در روش همزمان، در این مثال ارسال بسته ها به صورت همزمان انجام می شود و درواقع سرعت عملکرد انتقال بسیار بالا می رود، با این حال برای انجام فرآیند ارسال همزمان یا async منابع به صورت مستقیم درگیر آن می شوند.
✅حالا که با مکانیزم فرآیند اجرای همزمان و غیرهمزمان آشنا شدیم، اجازه بدید تا یک مثال واقعی تر و در فضای برنامه نویسی بزنیم.
فرض می کنیم که قصد خواندن 5 فایل (متنی txt) را داریم:
📌در حالت sync یا غیرهمزمان بنا به حجم و طول فایل ها، زمان خواندن فایل متفاوت است و اگر تا خوانده نشدن کامل فایل قبلی، فایل بعد اجرا و خوانده نمی شوند، خوب اینکار در سیستم های رایانه ای که از منابع سخت افزاری ضعیفی بهره می برند کار بسیار منطقی است.
📌اما گاهی نیاز داریم تا هر 5 فایل را به صورت همزمان بخوانیم، در این حالت باید سراغ فرآیند async یا همزمان برویم، اما این روش با وجود تمام خوبی هایی که دارد، یک نقطه ضعف نیز دارد که آنهم مصرف بیش از حد منابع سخت افزاری از جمله Ram و Cpu می باشد.
برای مثال واقعی تر، قصد داریم تا تابع زیر را اجرا کنیم:
void run()
{
for (int i = 0; i < 500; i++)
{
listView1.Items.Add(i);
Thread.Sleep(1000);
}
}
این تابع اگر به صورت کاملا عادی مانند زیر فراخوان شود:
private void button1_Click(object sender, EventArgs e)
{
//sync
run();
}
چندحالت به وجود می آید:
- اینکه فرم برنامه تا اتمام کار قفل می شود
- تا زمانیکه حلقه به انتها نرسیده باشد، عملا هیچ دستور دیگری اجرا نمی شود.
- امکان غیر فعال کردن حلقه، در زمان اجرا ممکن نیست
- در حالت عادی هر شمارش 1 ثانیه زمان می برد و زمانیکه در 500 ضرب کنیم، زمانی معادل 500 ثانیه همه چیز قفل می شود
- در واقع چیزی معادل 8 دقیقه و 30 ثانیه زمان می برد تا فراخوان تابع مورد نظر اتمام بشود.
اما در حالت همزمان یا Async مشکلی در 3 حالت قبل نداریم و عملا همه چیز به قدرت سیستم ما وابستگی خواهد داشت.
- فرم قفل نمی شود
- می توان چندین دستور دیگر را نیز اجرا کنیم
- امکان خروج از حلقه و غیرفعال کردن فرآیند ممکن است
- مدت زمان پایان بسته به منابع سخت افزاری ما است ولی دخالتی در اجرای سایر برنامه ها ندارد.
نمونه کد فراخوان همزمان:
private void button2_Click(object sender, EventArgs e)
{
//async
var t = new ThreadStart(run);
var async = new Thread(t);
async.Start();
}
✅نکته من از var برای تعریف متغیر ها استفاده کردم که سرعت کار بالا تر برود
در این کد خط اول باعث می شود تا تابع مورد نظر را در یک نخ جدید (Thread) تعریف کنیم (در پرانتز تابع مورد نظر خود را وارد کنیم):
var t = new ThreadStart(run);
سپس در خط بعد یک نخ دیگر می سازیم که وظیفه آن هندل کردن و اجرای تابع تعریف شده در خط قبل می باشد.
✅به سادگی می توان حتی در حین اجرا بودن این فرآیند (نخ) آن را غیرفعال یا مجددا اجرا کنیم.
و در نهایت در خط آخر نخ مورد نظر را اجرا می کنیم:
async.Start();