Software engineer
چجوری Channel ها در Golang کار میکنن
در این پست میخوایم راجب اینکه channel ها چطور کار میکنن و نحوه ی ارسال/دریافت دیتا روی اون ها به چه شکل هست صحبت کنیم.
در گو همزمانی فقط در سینتکس خلاصه نمیشه . بلکه یک الگوی طراحی هست بدلیل اینکه :
همزمانی نیاز به همگام سازی دارد.
و گو برای رسیدن به این هدف از الگویی به نام CSP استفاده میکنه ( Communicating Sequential Processes) . و فلسفه اصلی همزمانی در گو به این صورت هست که :
برای برقراری ارتباط ، حافظه رو به اشتراک نذارید بلکه حافظه رو با برقراری ارتباط به اشتراک بزارید.
گوروتین یک thread سبک هست که توسط Go runtime مدیریت میشه و میتونه وظایف را به طور همزمان و به طور بالقوه به صورت موازی نیز اجرا کنه.
خب بیاین برای شروع یک buffered channel بسازیم:
ch := make(chan int, 3)
کد بالا یک Buffered Channel با ظرفیت ۳ و از نوع int
میسازه.
در عمق ماجرا تابع make
یک شی از نوعhchan
داخل heap میسازه و یک اشاره گر که به اون اشاره میکنه رو بر میگردونه . یه سری از فیلد های ساختار hchan
تو تصویر زیر اومده:
- فیلد
buf
: یک اشاره گر به یک ارایه هست که نقش صف را دارد (فقط برای buffered channel استفاده میشود). - فیلد
sendx
: ایندکس عنصر ارسالی در آرایه بافر - فیلد
recvx
: ایندکس عنصر دریافتی در آرایه بافر - فیلد
lock
: باعث میشه مطمئن بشیم که خواندن و نوشتن روی channel بصورت atomic انجام بشه
در ادامه میخوایم سناریو های زیر رو بررسی کنیم:
- ارسال و دریافت بدون بلاک شدن
- دریافت از یک channel خالی
- ارسال روی channel ای که پر هست
ارسال و دریافت بدون بلاک شدن:
وقتی که channel خالی باشه ما میتونیم آیتم هارو در صف بدون اینکه بلاک بشیم وارد کنیم.
و همین طور زمانی که channel خالی نباشه ما میتونیم آیتم هارو از جلوی صف بدون اینکه بلاک بشیم دریافت کنیم.
گوروتین های منتظر:
دو فیلد دیگه هست که زمانی که گوروتین های منتظر داریم خیلی برای ما مهم هستن :
- فیلد
recvq
: گوروتین های بلاک شده ای که سعی داشتن از channel دیتا بخونن رو نگهداری میکنه. - فیلد
sendq
: گوروتین های بلاک شده ای که سعی داشتن به channel دیتا بفرستند رو نگهداری میکنه.
درضمن recvq
, sendq
از جنس linked list هستن.
type hchan struct {
buf unsafe.Pointer
sendx uint
recvx uint
lock mutex
sendq waitq
recvq waitq
... // more fields
}
type waitq struct {
first *sudog
last *sudog
}
// pseudo goroutine
type sudog struct {
g *g
elem unsafe.Pointer
next *sudog
prev *sudog
...
c *hchan
}
دریافت از یک channel خالی:
زمانی که channel خالی هست عملیات خواندن از اون باعث بلاک شدن اون گوروتین میشه.
فراموش نکنید که همه ی گوروتین هایی که ار انتظار دریافت هستن داخل صف recvq
قرار میگیرن
راستی حواستون باشه که os thread بلاک نمیشه و فقط گوروتین بلاک میشه.
خب حالا سوال پیش میاد که این گوروتین بلاک شده کی دوباره شروع به کار میکنه ؟؟؟
همون طور که حدس میزنین جوابش میشه وقتی که یه گوروتین دیگه چیزی روی این channel بفرسته!
بیاین باهم یه بررسی بکنیم ببینیم چه اتفاق هایی رخ میده:
- گوروتین جدید دیتا ای رو که میخواد بفرسته رو مستقیم کپی میکنه داخل element اولین گوروتین ای که در صف منتظره !!!!!!!!!!!!!!!!!!
- اولین گوروتین در حال انتظار از recvq برداشته و از صف حدف میشه.
- حالا runtime scheduler گوروتین برداشته شده رو داخل runqueue میذاره . بنابرین الان گوروتین بلاک شده آمادست که دوباره اجرا بشه.
احتمالا خیلی شوکه شدین از اینکه وقتی بافر خالی باشه گوروتینی که میخواد دیتا رو بفرسته داخل channel مستقیم اون رو کپی می کنه داخل elem گوروتین ای که منتظر هست و اول دیتارو داخل بافر نمی فرسته
برای این انقدر عجیبه که گوروتین ها برای خودشون stack جدا دارن و معمولا هیچ وقت گوروتین ها از stack گوروتین دیگه ای به طور مستقیم نمیخونن و نمی نویسن . فقط در این حالته که گوروتین ها همچین کاری میکنن. و دلیلش هم بهبود پرفورمنس هست.
ارسال روی channel ای که پر هست
زمانی که channel پر هست عملیات ارسال به اون باعث بلاک شدن گوروتین میشه.
تا وقتی که یک گوروتین دیگه از channel چیزی دریافت کنه بقیه گوروتین ها بلاک شده باقی میمونن.
بیاین جزییاتش رو باهم بررسی کنیم:
- زمانی که یک گوروتین جدید عملیات خوندن از channel رو انجام میده , اولین عنصر موجود در بافر پاک میشه
- اولین گوروتین منتظر از صف
sendq
برداشته و حذف میشه - مقدار element گوروتین برداشته شده داخل بافر کپی میشه
- حالا runtime scheduler گوروتین برداشته شده رو داخل runqueue میذاره . بنابرین الان گوروتین بلاک شده آمادست که دوباره اجرا بشه
امیدوارم که این پست تونسته باشه خلاصه ای از نحوی کار channel ها توی Golang رو شرح بده
از این که زمان گذاشتید و این پست رو خوندید خیلی ممنون . خوشحال میشم اگه این پست رو خوندید در کامنت ها نظرات خودتون رو مطرح کنید.
منابع:
مطلبی دیگر از این انتشارات
کار با داده از نزدیک چه شکلیه؟
مطلبی دیگر از این انتشارات
مدیریت مدرن چیست؟
مطلبی دیگر از این انتشارات
قسمت سی و پنج رمان منجلاب خون نویسنده مبینا ترابی