در مطلب قبلی کمی درمورد قابلیت های گو در همزمانی صحبت کردیم و اولین قدم هایمان را رفتیم٬ در این جا در مورد چنل ها گمی بیشتر حرف می زنیم
چنل ها (channels) یک راه ارتباط است برای گوروتین ها بطوری که داده ای را که در گوروتین ها و تابع اصلی احتیاج داریم ذخیره می کنیم و در مواقع بعد آنرا دریافت می کنیم
یک برنامه جمع کوچیک که از چنل ها در ان استفاده شده می نویسیم
package main import ( "fmt" "time" ) 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("num:%d,\tsum:%d\n", 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 <- "Go is fun!" }
در تابع fun از پارامتر ch بهره میبریم و داده مورد نظر را می فرستیم (یا ذخیره می کنیم)
ch := make(chan string) go fun(ch) fmt.Println(<-ch)
و در تابع اصلی داده را دریافت کرده و آنرا نمایش می دهیم!!
بعضی وقت ها تو برنامه مون شرایظی پیش می آید که هیج گوروتینی اجرا نمی شود و همه متوقف شده اند. راه های مختلفی برای deadlock درست کردن؛ مثلا همان برنامه قبل٬ اگه فقط تو تابع main یا تابع fun دستکاری کنیم خطا میده.
func fun(ch chan string) { fmt.Println("Go is fun!") // no sending ! }
ch := make(chan int) go fun(ch) fmt.Println(<-ch) fmt.Println(<-ch) // receiving twice !
و با همجین جیزی مواجهه میشویم!
شايد از راه حل ها استفاده از buffered channels باشد!
مانند چنل های معمولی اند ولی طرفیت چنل را محدود میکنند٬ یک پارامتر به آن اضافه می کنیم (پیش فرضش 0 است) و این باعث تغییر بافر (یا ظرفیت) به اندازه دلخواه باشد.
یه مثال کوجک
func main() { ch := make(chan string, 2) ch <- "Golang" ch <- "channels" fmt.Println(<-ch) fmt.Println(<-ch) }
نکته -> ارسال کننده وقت پرشدن چنل هیج جی نمی تونه بفرسته؛ دریافت کننده تا زمان خالی شدن چنل می تونه داده بگیره
تو این مطلب آموختیم که جنلها (channels) داده ها را به گوروتین های مختلف با کمترین دردسر انتقال می دهند٬ فقط کافیه یک متغیر با تایپ همسان تعریف کنیم بعد با '->' می تونیم داده را ذخیره (ارسال) و رها (دریافت) کنیم٬ البته میتونیم ظرفیت جنل هایم مشخص کنیم ...
امیدوارم لذت برده باشید :-)