منبع اصلی نوشتار زیر در این لینک قرار دارد

غواصی در اعماق: تفاوت goroutine ها در go و Threadهای معمول

خب اینم یه تجربه پراکنده دیگه!

من یه مدته که دارم golang رو یاد میگیرم. تاحالا بخاطر اینکه تجربه قابل قبول خوبی توی این یادگیری وجود نداشت چیزی ننوشته بودم. اما اخیرا به یه موضوع توی این زبان علاقه مند شدم و رفتم و ته توش رو در اوردم که به نظر جالب اومد که اینجا هم بنویسمش.

یکی از ویژگی‌هایی که go وجود داره اینه که خود زبان بصورت توکاری شده از یه مفومی به نام goroutine ها پشتیبانی می‌کنه. goroutine ها یه ابزاری برای ایجاد همروندی در برنامه است و تقریبا نحوه استفاده از اونها شبیه جاهایی است که ما از Thread ها استفاده می‌کنیم. یعنی هر جایی که بخوایم عملیاتی رو که به هر دلیل بلوکه میشه رو انجام بدیم و نمیخوایم اصل برنامه گیر کنه ازش استفاده می‌کنیم. واسه من این سوال بوجود اومد که خب اگه اینقدر این دوتا شبیه هستن چرا اسمشون شده دوتا و این جا بود که تحقیقات شروع شد:

اول از همه بگذارید یکم بگم Thread یا goroutine چیه:

  • خب Thread و goroutine ها هر کدام Stack متفاوتی دارند. یعنی متغیرهای محل مختص به خودشون رو دارن!
  • همه Thread ها و goroutineها بخش Data Segment یکسانی دسترسی دارند. یعنی متغیرهای عمومی برنامه رو می‌بینند.
  • همه Threadها و goroutineها بخش Code Segment یکسانی دسترسی دارند. یعنی توابع کل برنامه رو میبینن
  • همه Threadها و goroutineها بخش Heap Segment یکسانی دسترسی دارند. یعنی به شیٔ هایی که در برنامه new شدن دسترسی دارن

حالا نوبت تفاوتهاست:

  • اولین تفاوت در سایز stack بود.
    • یعنی اینکه به ازای هر Thread جدید سیستم عامل نزدیک به ۲ مگ و دیده شده تا ۸ مگ حافظه به stack اون Thread اختصاص میده و این درحالیه که هر goroutine در یسری نسخه‌ها ۴ کیلو بایت و در یسری نسخه جدید تر ۸ کیلو بایت حافظه اختصاص میده
    • سایز stack در Threadها در طول اجرا تغییر نمیکنه یعنی این سایز همین مقدار میمونه ولی سایز stack در goroutineها بر اساس نیاز زیاد میشه.
    • نتیجه تفاوت حجم هم اینها هستن
      • همین تفاوت حجم باعث میشه که وقتی یک گیگ مموری داریم میتونیم بین ۱۲۸ تا ۵۱۲ Thread بسازیم ولی میتونیم حدودا ۱۲۸۰۰۰ تا ۲۵۶۰۰۰ goroutine بسازیم.
      • همین تفاوت حجم باعث میشه ساختن و پاک کردن goroutine ها بسیار کم هزینه تر از Thread ها باشه
  • دوم تفاوت هم نحوه زمانبندی برای اجراست:
    • threadها توسط سیستم عامل زمانبندی شده و اجرا میشن که با توجه به حجم stack معمولا کار پر هزینه‌ای است
    • goroutine ها در محیطی به نام go runtime هست که کل کدها توی اون اجرا میشن. یعنی اینکه go runtime مسئول لود کرد حافظه مورد نیاز برای goroutineها رو بر عهده داره. همچنین زمانبندی اجرا هم توسط همین محیط انجام میشه. این محیط خودش از یک یا چند Thread تشکیل شده که goroutine ها رو اجرا میکنن و عین اینه که شما یه سری کار رو بصورت اتوماتیک به یک Thread pool داده باشی. به همین خاطر کل این روند بسیار از نظر برنامه نویس ساده شده. همچنین وجود این go runtime این امکان رو بوجود آورده که از الگوریتم‌های زمانبندی بهینه تری برای این زبان استفاده بشه که خودش افزایش کارایی رو نتیجه میده. البته این روش معایبی هم داره که اگر عمری بود در موردش مینویسم.
  • سومین تفاوت هزینه بازگذاری و خروج از مموری:
    • برای اجرای Thread ها تقریبا تمام رجیسترهای سی پی یو (شامل  ۱۶ رجیستر عمومی، PC، SP، رجیسترهای سگمنت و …) تغییر میکند. که در مواردی که تغییر بین Threadها زیاد است هزینه قابل توجهی است.
    • در goroutine ها تنها سه رجیستر(SP, PC, DX) تغییر میکند.

فعلا همین!