abbas80
abbas80
خواندن ۳ دقیقه·۶ ماه پیش

نگاهی مختصر به concurrency در Go: چنل ها


آشنایی با channel ها

در مطلب قبلی کمی درمورد قابلیت های گو در همزمانی صحبت کردیم و اولین قدم هایمان را رفتیم٬ در این جا در مورد چنل ها گمی بیشتر حرف می زنیم

چنل ها (channels) یک راه ارتباط است برای گوروتین ها بطوری که داده ای را که در گوروتین ها و تابع اصلی احتیاج داریم ذخیره می کنیم و در مواقع بعد آنرا دریافت می کنیم


یک برنامه جمع کوچیک که از چنل ها در ان استفاده شده می نویسیم

package main import ( &quotfmt&quot &quottime&quot ) var ( input = 10 ) func main() { a := make(chan int) b := make(chan int) mid := input / 2 go sumIt(0, mid, a) // first numbers go sumIt(mid+1, input, b) // last numbers result := <-a + <-b // receiving data ; sumUp fmt.Println(result) } func sumIt(start, stop int, res chan int) { defer close(res) // make sure to close channel sum := 0 for i := start; i <= stop; i++ { sum += i fmt.Printf(&quotnum:%d,\tsum:%d\n&quot, i, sum) time.Sleep(100 * time.Millisecond) } res <- sum // sending data }

این برنامه جمع را با دو تابع انجام می دهد!


ch := make(chan string) go fun(ch)

شیوه استفاده از channels: اول یک متغیر از نوع چنلو با هر دیتا تایپی دوست دارید٬ با تابع make ایجاد می کنیم و اون رو به تابع پاس می دهیم

func fun(ch chan string) { ch <- &quotGo is fun!&quot }

در تابع fun از پارامتر ch بهره میبریم و داده مورد نظر را می فرستیم (یا ذخیره می کنیم)

ch := make(chan string) go fun(ch) fmt.Println(<-ch)

و در تابع اصلی داده را دریافت کرده و آنرا نمایش می دهیم!!

  • توجه : -> برای ارسال و دریافت داده ها به کار میرود٬ اگه بعد از متغیر باشد داده ارسال میشود واگه قبلش باشه داده دریافت میشود
  • توجه : -> فقط یکبار می توانیم از آن داده ارسال و دریافت کنیم (نه بیشتر) مگر در شرایط خاص!
  • توجه : -> باعث میشود که دریافت کننده صبر کند تا داده مورد نظر ارسال کننده بفرستد

شرح deadlock

بعضی وقت ها تو برنامه مون شرایظی پیش می آید که هیج گوروتینی اجرا نمی شود و همه متوقف شده اند. راه های مختلفی برای deadlock درست کردن؛ مثلا همان برنامه قبل٬ اگه فقط تو تابع main یا تابع fun دستکاری کنیم خطا میده.

func fun(ch chan string) { fmt.Println(&quotGo is fun!&quot) // no sending ! }


ch := make(chan int) go fun(ch) fmt.Println(<-ch) fmt.Println(<-ch) // receiving twice !

و با همجین جیزی مواجهه میشویم!

خطا: توقف همه گورتینها
خطا: توقف همه گورتینها

شايد از راه حل ها استفاده از buffered channels باشد!

نگاهی به buffered channels

مانند چنل های معمولی اند ولی طرفیت چنل را محدود میکنند٬ یک پارامتر به آن اضافه می کنیم (پیش فرضش 0 است) و این باعث تغییر بافر (یا ظرفیت) به اندازه دلخواه باشد.

یه مثال کوجک

func main() { ch := make(chan string, 2) ch <- &quotGolang&quot ch <- &quotchannels&quot fmt.Println(<-ch) fmt.Println(<-ch) }

نکته -> ارسال کننده وقت پرشدن چنل هیج جی نمی تونه بفرسته؛ دریافت کننده تا زمان خالی شدن چنل می تونه داده بگیره


جمع بندی

تو این مطلب آموختیم که جنلها (channels) داده ها را به گوروتین های مختلف با کمترین دردسر انتقال می دهند٬ فقط کافیه یک متغیر با تایپ همسان تعریف کنیم بعد با '->' می تونیم داده را ذخیره (ارسال) و رها (دریافت) کنیم٬ البته میتونیم ظرفیت جنل هایم مشخص کنیم ...

امیدوارم لذت برده باشید :-)

گوگولنگزبان گو
شاید از این پست‌ها خوشتان بیاید