channel คือท่อส่งข้อมูลที่มีชนิดสำหรับ การสื่อสารระหว่าง goroutine — goroutine หนึ่งส่งค่า อีก goroutine หนึ่งรับ channel คือวิธีที่ goroutine ของ Go ส่งข้อมูลและ synchronize อย่างปลอดภัย เป็นการสะท้อนคติพจน์ "share memory by communicating"
การสร้างและใช้งาน channel
ch := make(chan int) // an unbuffered channel of ints
go func() {
ch <- 42 // SEND a value into the channel (arrow points INTO ch)
}()
value := <-ch // RECEIVE a value from the channel (arrow points OUT)
fmt.Println(value) // 42
ตัวดำเนินการ <- ใช้ทั้งส่ง (ch <- v) และรับ (v := <-ch)
unbuffered เทียบกับ buffered channel
// UNBUFFERED — send blocks until a receiver is ready (synchronization point)
ch := make(chan int)
// sending blocks until another goroutine receives → they "rendezvous"
// BUFFERED — holds up to N values; send blocks only when the buffer is FULL
buf := make(chan int, 3)
buf <- 1; buf <- 2; buf <- 3 // these don't block (buffer has room)
buf <- 4 // blocks now — buffer is full
channel แบบ unbuffered จะ synchronize: การส่งจะรอการรับ (และในทางกลับกัน) ทำให้มันเป็นเครื่องมือประสานงาน ส่วน channel แบบ buffered จะแยกผู้ส่งและผู้รับออกจากกันได้จนถึงขนาดของ buffer
การปิด channel และการ range
ch := make(chan int)
go func() {
for i := 0; i < 3; i++ { ch <- i }
close(ch) // signal "no more values" (only the SENDER closes)
}()
for v := range ch { // receives until the channel is CLOSED
fmt.Println(v)
}
// the comma-ok form detects a closed channel
v, ok := <-ch // ok = false if the channel is closed and drained
การปิด channel เป็นสัญญาณว่าทำงานเสร็จแล้ว ส่วน range บน channel จะรับค่าจนกว่ามันจะถูกปิด ผู้ส่งเท่านั้นที่ควรปิด channel
กับดัก deadlock และ panic ที่พบบ่อย
// ❌ deadlock — sending on an unbuffered channel with no receiver
ch := make(chan int)
ch <- 1 // 💥 fatal error: all goroutines asleep - deadlock!
// ❌ panic — operations on/after close
close(ch); close(ch) // 💥 panic: close of closed channel
close(ch); ch <- 1 // 💥 panic: send on closed channel
v := <-closedCh // ✅ OK — receiving from a closed channel returns the zero value
deadlock (ทุกตัวถูก block) และ panic ที่เกี่ยวกับการปิดเป็นบั๊กของ channel ที่พบบ่อยและต้องทำความเข้าใจ
directional channel (เพื่อ API ที่ชัดเจน)
func producer(out chan<- int) { out <- 1 } // send-only
func consumer(in <-chan int) { <-in } // receive-only
ทำไมจึงสำคัญ
channel เป็นหัวใจของโมเดล concurrency ของ Go และเป็นวิธีที่เป็นสำนวนสำหรับ goroutine ในการสื่อสารและ synchronize — เป็นการนำปรัชญาหลัก "don't communicate by sharing memory; share memory by communicating" มาใช้ มันช่วยให้คุณส่งข้อมูลอย่างปลอดภัยระหว่าง goroutine ที่ทำงานพร้อมกันโดยไม่ต้องใช้ lock อย่างชัดแจ้ง สร้าง pipeline กระจายงาน และส่งสัญญาณว่าทำงานเสร็จ
การเข้าใจการดำเนินการส่ง/รับ ความแตกต่างที่สำคัญระหว่าง unbuffered (synchronizing) เทียบกับ buffered (decoupling) ความหมายของการปิด (ผู้ส่งเป็นคนปิด; range/comma-ok ตรวจจับได้) และกับดักที่พบบ่อย (deadlock จากการส่ง/รับที่ถูก block, panic จากการปิดซ้ำหรือส่งบน channel ที่ปิดแล้ว) เป็นสิ่งจำเป็นสำหรับการเขียน Go แบบ concurrent ที่ถูกต้อง
channel (พร้อมกับ goroutine) เป็นหัวใจของอัตลักษณ์ของ Go และเป็นหนึ่งในแนวคิดที่สำคัญและถูกถามบ่อยที่สุดในภาษานี้
