زمانی که درخواستی به برنامه Net. ارسال میشود, برای هندل کردن درخواست یک Thread ایجاد میشود. زمانی که یک Thread ایجاد میشود مقداری منابع مانند مموری به Thread اختصاص می یابد. و در نهایت زمانی که کار انجام میشود Garbage Collector, ابجکت ایجاد شده برای Thread را از بین میبرد. چرخه عمر Thread به این صورت هست:

  • درخواست ارسال میشود
  • ابجکت Thread ایجاد میشود
  • منابع مورد نظر مانند مموری به Thread اختصاص می یابد.
  • کار انجام میشود
  • Garbage Collector فضای اشغال شده را از بین میبرد

این کار به صورت مکرر در حال اجراست و این بدان معناست که برای هر درخواست یک Thread جدید ایجاد میشود و مقداری از منابع را به خود اختصاص میدهد. اگر درخواست ها افزایش یابد Thread های زیادی ایجاد میشوند و اگر تعداد Thread ها زیاد شود به دلیل اختصاص مموری باعث کندی سیستم میشود.

اما نحوه کار Thread pool کمی متفاوت است:

 Thread pool یک مجموعه ای از Thread هاست که میتوانند مجددا استفاده شوند. یعنی زمانی که یک درخواست ارسال میشود ابتدا Thread pool بررسی میشود که Threadی وجود دارد که آزاد باشد یا نه. اگر موجود باشد یک Thread از Thread pool دریافت میکند و کار را انجام میدهد و زمانی که کار توسط Thread انجام میشود مجددا Thread به Thread pool بازگردانده میشود تا بتوان مجدد از آن استفاده کرد. این قابلیت از ایجاد Thread های زیاد جلوگیری میکند و باعث میشود که حافظه کمتری مصرف شود. اما اگر در Thread poolهیچ Threadی در دسترس نباشد, کارهای مورد نیاز درون صف قرار میگیرند تا Thread در اختیارشان قرار بگیرد. 

هدف اصلی Thread pool جلوگیری از ایجاد Thread های زیاد برای کارهای کوچک و کوتاه مدت است.

یکی دیگر از موضوعات مهم Thread.Sleep و Task.Delay هستند. Task.Delay برای کدهای async ایجاد شده است.  زمانی که از Thread.Sleep استفاده کنید Thread جاری بلاک میشود ( با توجه مقدار زمان داده شده ) و نمیتوان از این Thread در جایی دیگر استفاده کرد.

به طور معمول کدهایی که به صورت async نوشته میشود بر روی Thread pool اجرا میشود و اصلا نباید از Thread.Sleep در کدهای async استفاده کرد چون باعث کاهش کارایی سیستم خواهند شد چون Thread جاری را بلاک میکند و اجازه کار دیگری را نمیدهد درحالی که میتوان از این Thread برای انجام کار دیگری استفاده کرد و عملا مزایای Thread pool را از بین میبرند.

اگر بخواهید متد شما Thread را از Thread pool دریافت کند میتوانید از Task.Run و یا ThreadPool.QueueUserWorkItem استفاده کنید. هر دوی این دستورات یک Thread از Thread pool دریافت میکنند.

تفاوت دیگر Thread پیشفرض  و Thread ی که از Thread pool  دریافت شده است به این صورت است که Thread ها به صورت پیشفرض در Thread pool به صورت پس زمینه ( background ) اجرا میشوند. یعنی زمانی که Threadهای اصلی که به صورت پیش زمینه (foreground ) اجرا شده اند, خاتمه یابند Thread هایی که از Thread pool دریافت شده اند نیز خاتمه میابند و به کار خود ادامه نمیدهند. اما Threadهایی که صورت پیش زمینه اجرا میشوند, اگر یک Threadی باشد که به صورت پیش زمینه کار کند, تا زمانی که این Thread کارش تمام نشود برنامه خاتمه نمی یابد. 

در کد زیر در مرحله اول چون متد DoSomething توسط Thread pool اجرا میشود و به صورت پیشفرض به صورت پس زمینه کار میکند, قبل از اینکه کار متد DoSomething تمام شود برنامه Stop میشود.

public static void Main()
{
    // Queue the task.
    ThreadPool.QueueUserWorkItem(DoSomething);
    Console.WriteLine("Main thread does some work, then sleeps.");  
    Console.WriteLine("Main thread exits.");
}
static void DoSomething(Object stateInfor)
{
    Thread.Sleep(5000);
    Console.WriteLine("Hello from the thread pool.");
}

خروجی به صورت زیر میباشد:

Main thread does some work, then sleeps.
Main thread exits.

C:\Program Files\dotnet\dotnet.exe (process 10396) exited with code 0.
Press any key to close this window . . .

چون متد DoSomething به صورت پس زمینه اجرا شده است, Thread اصلی برنامه صبر نمیکند تا کار Threadی که کار متد DoSomething را انجام میدهد تمام شود و برنامه خاتمه میابد. اما اگر خاصیت IsBackground مربوط به Threadی را که کار متد DoSomething را انجام میدهدبرابر false کنیم, Thread اصلی برنامه صبر میکند تا کار متد DoSomething تمام شود سپس برنامه خاتمه یابد.

public static void Main()
{
    // Queue the task.
    ThreadPool.QueueUserWorkItem(DoSomething);
    Console.WriteLine("Main thread does some work, then sleeps.");     
    Console.WriteLine("Main thread exits.");
}
static void DoSomething(Object stateInfor)
{
    Thread.CurrentThread.IsBackground = false;
    Thread.Sleep(5000);
    Console.WriteLine("Hello from the thread pool.");
}

و خروجی زیر را دریافت میکنید:

Main thread does some work, then sleeps.
Main thread exits.
Hello from the thread pool.

C:\Program Files\dotnet\dotnet.exe (process 7640) exited with code 0.
Press any key to close this window . . .

همچنین اگر میخواهید بدانید که Thread جاری از Thread pool دریافت شده است یا نه میتوانید از کد زیر استفاده کنید:

Thread.CurrentThread.IsThreadPoolThread;

برای مشخص کردن Thread که آیا به صورت پیش زمینه یا پس زمینه اجرا شده است میتوانید از کد زیر استفاده کنید:

bool isBackgroundThread = Thread.CurrentThread.IsBackground;

لیست منابع :

;)

نظرات