
Channel یکی از کلیدیترین مؤلفههای مدل همزمانی در زبان Go است. در حالی که Goroutineها امکان اجرای موازی و سبکوزن را فراهم میکنند، این Channelها هستند که ارتباط کنترلشده و امن بین آنها را ممکن میسازند. بدون Channel، مدیریت هماهنگی میان Goroutineها میتواند بسیار پیچیده و خطاپذیر باشد.
در این مقاله، به صورت کاملاً عملی و دقیق بررسی میکنیم که Channel چیست، چگونه کار میکند و چه الگوهایی در توسعه همزمان با آن استفاده میشود.
Channel یک سازوکار داخلی در Go است که امکان ارسال و دریافت داده را بین Goroutineها فراهم میکند. Channel نوعمحور است؛ یعنی تنها دادهای از یک نوع مشخص را قبول میکند. به بیان ساده:
Channel = لولهای برای عبور داده بین goroutineها بهصورت همزمان و ایمن.
Channel دو ویژگی مهم دارد:
همگامسازی (Synchronization)
ارسالکننده و گیرنده برای انتقال داده همگام میشوند.
ایمن از رقابت (Race-Free)
چون Channel کنترل ارسال و دریافت را مدیریت میکند، نیاز به لاک و Mutex در بسیاری از سناریوها کاهش مییابد.
ch := make(chan int)
این دستور یک Channel از نوع int ایجاد میکند.
ارسال داده:
ch <- 10
دریافت داده:
value := <-ch
ارسالکننده تا زمانی که گیرنده آماده دریافت نباشد، بلوکه میشود و بالعکس.
package main import ( "fmt" ) func main() { ch := make(chan string) go func() { ch <- "Hello from goroutine" }() msg := <-ch fmt.Println(msg) }
در این مثال، داده از یک Goroutine به Goroutine اصلی منتقل میشود.
به صورت پیشفرض، Channel فاقد بافر است. یعنی:
ارسال و دریافت باید همزمان انجام شوند
حالت کاملاً همگام است
ch := make(chan int)
Channel میتواند یک بافر داخلی داشته باشد:
ch := make(chan int, 3)
در این حالت:
ارسال تا زمانی که بافر پر نشده بلوکه نمیشود
دریافت تا زمانی که بافر خالی نشده بلوکه نمیشود
مثال:
ch := make(chan int, 2) ch <- 1 ch <- 2 // OK ch <- 3 // بلوکه میشود
از close() برای اعلام پایان ارسال داده استفاده میشود.
close(ch)
نکات مهم:
بعد از close امکان ارسال وجود ندارد
دریافتکننده میتواند با بررسی مقدار دوم بفهمد Channel بسته شده است
مثال:
v, ok := <-ch if !ok { fmt.Println("channel closed") }
برای دریافت داده تا زمان بسته شدن Channel:
for v := range ch { fmt.Println(v) }
Channel برای توزیع کار میان چند Goroutine استفاده میشود.
یک منبع داده به چند Goroutine پخش (fan-out) میشود و سپس نتایج در یک Channel جمعآوری (fan-in) میشود.
Channel میتواند برای نشانهگذاری پایان یک کار یا شروع عملیات استفاده شود.
select به شما اجازه میدهد از چند منبع همزمان داده دریافت یا ارسال کنید.
select { case v := <-ch1: fmt.Println("received:", v) case ch2 <- 10: fmt.Println("sent to ch2") default: fmt.Println("no communication") }
Channel را فقط ارسالکننده ببندد
از Buffer زمانی استفاده کنید که دلیل مشخص دارید
برای جلوگیری از deadlock همیشه سناریوی دریافتکننده/ارسالکننده را بهدقت طراحی کنید
از select همراه با timeout استفاده کنید
مثال timeout:
select { case v := <-ch: fmt.Println(v) case <-time.After(time.Second): fmt.Println("timeout") }
Channel یکی از قدرتمندترین ابزارهای همزمانی در Go است که امکان ارتباط ایمن، ساده و کارآمد بین goroutineها را فراهم میکند. استفاده صحیح از channelها میتواند معماری همزمان برنامه شما را بسیار تمیزتر و قابلنگهداریتر کند.