همزمانی و پردازش چندنخی (Multithreading) در #C
همزمانی و پردازش چندنخی (Multithreading) در #C
در برنامهنویسی، پردازش چندنخی (Multithreading) به اجرای همزمان چندین بخش از کد اشاره دارد. این مفهوم به شما این امکان را میدهد که برنامههای سریعتر و کارآمدتری بنویسید، زیرا میتوانید از منابع سیستم بهطور بهینهتری استفاده کنید. بهویژه در مواقعی که نیاز به انجام عملیاتهای طولانیمدت (مانند خواندن از شبکه یا پردازشهای سنگین) دارید، استفاده از چند نخ میتواند عملکرد برنامه را بهبود بخشد.
در #C، میتوانید از کتابخانههای مختلف برای کار با نخها (threads) استفاده کنید. مهمترین ابزارها عبارتند از:
- کلاس Thread: برای ایجاد و مدیریت نخهای جدید.
- Task Parallel Library (TPL): برای مدیریت وظایف و عملیاتهای همزمان بهصورت سطح بالاتر.
- async و await: برای مدیریت برنامهنویسی ناهمزمان و تسهیل پردازشهای ورودی/خروجی.
۱. استفاده از کلاس Thread
در #C، میتوانید از کلاس Thread برای ایجاد و مدیریت نخها استفاده کنید. نخها به شما این امکان را میدهند که همزمان چندین کار را انجام دهید.
مثال ساده ایجاد نخ با کلاس Thread
using System.Threading;
class Program
{
static void Main()
{
// ایجاد و شروع نخ جدید
Thread thread = new Thread(PrintNumbers);
thread.Start(); // اجرای تابع PrintNumbers در نخ جدید
// ادامه کار در نخ اصلی
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Main Thread: " + i);
Thread.Sleep(1000); // تأخیر 1 ثانیه
}
// منتظر ماندن برای پایان یافتن نخ جدید
thread.Join();
}
static void PrintNumbers()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Worker Thread: " + i);
Thread.Sleep(500); // تأخیر 0.5 ثانیه
}
}
}
خروجی:
Worker Thread: 0
Main Thread: 1
Worker Thread: 1
Main Thread: 2
Worker Thread: 2
Main Thread: 3
Worker Thread: 3
Main Thread: 4
Worker Thread: 4
در این مثال:
- ما یک نخ جدید ایجاد کردهایم که در آن تابع PrintNumbers اجرا میشود.
- در نخ اصلی، از Thread.Sleep برای ایجاد تأخیر استفاده شده است.
- از متد Join برای منتظر ماندن تا پایان کار نخ استفاده کردهایم.
۲. استفاده از Task Parallel Library (TPL)
Task در #C یک مدل سطح بالاتر برای کار با نخها است که در Task Parallel Library (TPL) موجود است. Task مدیریت نخها را سادهتر کرده و امکان نوشتن برنامههای همزمان را با کارایی بالا فراهم میآورد.
مثال استفاده از Task برای پردازش همزمان
using System.Threading.Tasks;
class Program
{
static void Main()
{
// شروع یک Task جدید
Task task = Task.Run(() => PrintNumbers());
// ادامه کار در نخ اصلی
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Main Thread: " + i);
Task.Delay(1000).Wait(); // تأخیر 1 ثانیه
}
// منتظر ماندن برای پایان یافتن Task
task.Wait();
}
static void PrintNumbers()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Worker Task: " + i);
Task.Delay(500).Wait(); // تأخیر 0.5 ثانیه
}
}
}
خروجی:
Worker Task: 0
Main Thread: 1
Worker Task: 1
Main Thread: 2
Worker Task: 2
Main Thread: 3
Worker Task: 3
Main Thread: 4
Worker Task: 4
در این مثال:
- ما از Task.Run برای اجرای تابع PrintNumbers در یک وظیفه جدید استفاده کردیم.
- از Task.Delay برای ایجاد تأخیر استفاده شده است (شبیه به Thread.Sleep).
- با استفاده از ()task.Wait منتظر پایان یافتن وظیفه میمانیم.
۳. استفاده از async و await
برای پردازشهای ناهمزمان که بیشتر برای عملیاتهای ورودی/خروجی مانند خواندن از فایل، درخواستهای وب و یا بانک اطلاعاتی استفاده میشود، میتوان از کلمات کلیدی async و await استفاده کرد.
مثال استفاده از async و await برای پردازش ناهمزمان
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// فراخوانی یک تابع ناهمزمان
await PrintNumbersAsync();
// ادامه کار در نخ اصلی
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Main Thread: " + i);
await Task.Delay(1000); // تأخیر 1 ثانیه
}
}
static async Task PrintNumbersAsync()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Worker Task: " + i);
await Task.Delay(500); // تأخیر 0.5 ثانیه
}
}
}
خروجی:
Main Thread: 0
Worker Task: 1
Main Thread: 1
Worker Task: 2
Main Thread: 2
Worker Task: 3
Main Thread: 3
Worker Task: 4
Main Thread: 4
در این مثال:
- تابع PrintNumbersAsync بهطور ناهمزمان با استفاده از await فراخوانی شده است.
- با استفاده از Task.Delay بهطور غیر همزمان تأخیر ایجاد کردهایم.
۴. هماهنگی نخها (Thread Synchronization)
هنگامی که چند نخ به طور همزمان به منابع مشترک دسترسی دارند، ممکن است مشکلاتی مانند رقابت برای منابع (race condition) ایجاد شود. برای جلوگیری از این مشکلات، میتوانید از مکانیزمهای هماهنگی مانند lock و Monitor استفاده کنید.
مثال استفاده از lock برای هماهنگی نخها
using System.Threading;
class Program
{
static int counter = 0;
static readonly object lockObject = new object(); // شی برای قفل کردن
static void Main()
{
// ایجاد دو نخ که به متغیر counter دسترسی دارند
Thread t1 = new Thread(IncrementCounter);
Thread t2 = new Thread(IncrementCounter);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
// نمایش نتیجه
Console.WriteLine("Final counter value: " + counter);
}
static void IncrementCounter()
{
for (int i = 0; i < 1000; i++)
{
lock (lockObject) // قفل کردن بخش کد برای دسترسی همزمان نخها
{
counter++;
}
}
}
}
خروجی (با توجه به رقابت کمتر):
در این مثال:
- از کلمهکلیدی lock برای قفل کردن کد در داخل بخشهایی که به متغیر counter دسترسی دارند استفاده کردهایم تا از رقابت نخها جلوگیری شود.
جمعبندی
پردازش چندنخی و همزمانی در #C ابزارهایی قدرتمند برای بهبود عملکرد برنامهها هستند. شما میتوانید از کلاسهای Thread و Task برای مدیریت نخها استفاده کنید، و با استفاده از async و await به راحتی برنامهنویسی ناهمزمان انجام دهید. همچنین برای جلوگیری از مشکلات هماهنگی در هنگام دسترسی چندین نخ به منابع مشترک، از مکانیزمهای هماهنگی مانند lock استفاده میکنید.
