گفتگو هایی در باب سی شارپ

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
یادآوری و نکات تکمیلی درباره ی مدیریت استثنا در async await :

در حالت اجرا بدون استفاده از ویژال استودیو یا با حالت بدون دیباگ اش ، وقتی قسمتِ await را در try catch بذاریم ، exception هایی که در نخ جدید (که همون در Task های اجرا شده هست) پرتاب میکنیم ، هندل و مدیریت میشن .


  • متدهای Task.Factory.StartNew یا Task.Run یا Task.Start :

  • Task.Run و Task.Factory.StartNew هر دو برای ایجاد و زمان‌بندی اشیاء Task استفاده می‌شوند. Task.Run در واقع یک میانبر برای Task.Factory.StartNew است که با استفاده از مقادیر پیش‌فرضی برای پارامترها، یک Task را اجرا می‌کند. به عنوان مثال:
  • Task.Run(action);
  • معادل با:
  • Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
  • است.

  • اما Task.Factory.StartNew گزینه‌های بیشتری را در اختیار شما قرار می‌دهد و زمانی که نیاز به کنترل دقیق‌تری دارید، می‌توانید از آن استفاده کنید.

  • به عنوان مثال، اگر می‌خواهید یک Task طولانی را اجرا کنید و نمی‌خواهید از یک نخ از thread pool استفاده کنید، می‌توانید با استفاده از Task.Factory.StartNew و گزینه TaskCreationOptions.LongRunning، یک نخ جدید برای اجرای Task ایجاد کنید:
  • Task.Factory.StartNew(action, TaskCreationOptions.LongRunning);

  • در مورد Task.Start، باید بگویم که این متد فقط برای شروع یک Task استفاده می‌شود و نمی‌توانید با استفاده از آن یک Task را ایجاد کنید. به عنوان مثال:
  • var task = new Task(action);
  • task.Start();
  • وقتی یک Task را با استفاده از Task.Run یا Task.Factory.StartNew ، بصورت پیش فرض که بدون گزینه TaskCreationOptions.LongRunning است ، ایجاد می‌کنید، آن Task در یک نخ از thread pool اجرا می‌شود.

  • استفاده از یک نخ از thread pool برای اجرای یک Task طولانی ممکن است منجر به کاهش کارایی شود، زیرا thread pool تعداد محدودی نخ دارد و اگر تمام نخ‌های آن در حال اجرای Taskهای طولانی باشند، ممکن است سایر Taskها منتظر بمانند تا یک نخ آزاد شود. برای جلوگیری از این مشکل، می‌توانید با استفاده از گزینه TaskCreationOptions.LongRunning، یک نخ جدید برای اجرای Task ایجاد کنید:

  • Task.Factory.StartNew(action, TaskCreationOptions.LongRunning);

  • با استفاده از این گزینه، یک نخ جدید خارج از thread pool برای اجرای Task ایجاد می‌شود و thread pool در دسترس می‌ماند تا سایر Taskها را اجرا کند.
به طور کلی، اگر یک Task زمان زیادی را صرف انتظار برای پاسخ از یک منبع خارجی مانند پایگاه داده یا شبکه می‌کند، ممکن است به عنوان یک Task طولانی در نظر گرفته شود. در این حالت، استفاده از گزینه TaskCreationOptions.LongRunning
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
مهم :

همانطور که قبلا استاد گفته بودند ، struct و class ها ، هیچ ربطی به حافظه ی stack و heap نباید داشته باشند . یعنی بهتر اینکه به برنامه نویس مربوط نمیشود .

شی struct ، هر جایی که باشد (مثلا به عنوان مقدار یک متغییر باشد یا به عنوان مقدار عضوی از آرایه و ...) ، در همان حافظه کلا قرار میگیرد (چه در حافظه ی stack باشد یا heap) . اما reference type ها ، بصورت اشاره گر ، به حافظه ی دیگری اشاره میکنند .

مثلا متغییر محلی int a = 1; که از نوع struct هست ، در حافظه ی stack قرار میگیرد (که البته مهم هم نیست فرضا در استک باشد یا در هیپ ؛ یعنی صِرفِ اینکه چون در حافظه ی استک هست ، ممکن است دلیل بر این نباشد که سرعت دسترسی بالاتری دارد) .


اما آرایه ای از int ( یعنی int[] ) ، چون آرایه ، یک کلاس هست ، اشاره گر به حافظه ی heap دارد . اما آیتم هایش که از نوع struct هستند ، باز در همان آدرس از حافظه ی heap ای که آرایه قرار دارد ، قرار میگیرد . یعنی در این صورت ، آیتم های آرایه که از نوع struct هستند ، در حافظه ی stack قرار نمیگیرند .

مثلا در آرایه ی زیر :

C#:
int[] abc = new int[]{10, 20, 30};

فرضا اگر آرایه ی abc ، اشاره گر به خامه ی 1000 در حافظه ی heap باشد ، ایندکس 0 از این آرایه ، 4 بایت فضا دارد که مقدار int در آن هست (و همینطور بقیه ی ایندکس هایش هم 4 بایت فضا دارند). یعنی در اینجا شی int ، در حافظه ی stack قرار ندارد ؛ بلکه داخل حافظه ی heap قرار دارد .
(یعنی این طور نیست که چون int از نوع value type و struct هست ، پس در اینجا هم در حافظه ی stack قرار بگیرد و چون در این صورت ، آدرس stack ، جدای از حافظه ی heap هست ، پس ، آیتم های این آرایه ، اشاره گری به حافظه ی stack ئه نخ باشند) .

در مورد بقیه ی structهایی که خودمان بسازیم هم همینطور هست .
یعنی آن نوع های struct هم که ما تعریف میکنیم ، وقتی به عنوان آیتم های آرایه تعریف میشوند ، درون خود حافظه ی مربوط به آرایه (یعنی در heap) حافظه اشغال میکنند (یعنی در حافظه ی دیگری مثل stack قرار نمیگیرند که آیتم های آرایه ، اشاره گری به آن حافظه شوند) :

C#:
PicInfo[] ints = new PicInfo[3] { new PicInfo(1, 2), new PicInfo(20, 21), new PicInfo(30, 31) };
PicInfo[] ints_22 = new PicInfo[ints.Length];
ints.CopyTo(ints_22, 0);

ints[0] = new PicInfo(1500, 1600);

و

C#:
internal struct PicInfo
{
    public int x;
    public int y;

    public PicInfo(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

}

یعنی struct ها در هر حافظه ای که تعریف شوند ، همانجا قرار میگیرند و بصورت اشاره گر استفاده نمیشوند که این باعث میشود که چون پردازنده ، مجددا به سراغ حافظه ی دیگری نمیرود ، سرعت دسترسی اش بیشتر از reference type ها شود .

با تشکر از استاد و بقیه ی دوستان .
 

جدیدترین ارسال ها

بالا