← Danh sách bài học Bài 17/20

📡 Bài 17: Channel

⏱️ 25 phút | 📚 Nâng cao

🎯 Mục tiêu:

1. Channel Là Gì?

Channel là "ống dẫn" để goroutines giao tiếp và đồng bộ với nhau.

package main
import "fmt"

func main() {
    // Tạo channel kiểu string
    ch := make(chan string)
    
    // Goroutine gửi data
    go func() {
        ch <- "Hello!"  // Gửi vào channel
    }()
    
    // Main nhận data
    msg := <-ch  // Nhận từ channel
    fmt.Println(msg)  // Hello!
}
💡 Cú pháp:
ch <- value - gửi value vào channel
value := <-ch - nhận value từ channel

2. Unbuffered Channel

Channel mặc định là unbuffered - gửi sẽ block cho đến khi có goroutine nhận.

func main() {
    ch := make(chan int)  // Unbuffered
    
    go func() {
        ch <- 42  // Block đến khi có người nhận
    }()
    
    value := <-ch  // Nhận và unblock sender
    fmt.Println(value)
}

3. Buffered Channel

Có thể gửi mà không cần chờ nhận ngay (đến khi buffer đầy).

func main() {
    ch := make(chan int, 3)  // Buffer size = 3
    
    ch <- 1
    ch <- 2
    ch <- 3
    // ch <- 4  // Sẽ block vì buffer đầy!
    
    fmt.Println(<-ch)  // 1
    fmt.Println(<-ch)  // 2
    fmt.Println(<-ch)  // 3
}

4. Range và Close

func main() {
    ch := make(chan int)
    
    go func() {
        for i := 1; i <= 5; i++ {
            ch <- i
        }
        close(ch)  // Đóng channel khi xong
    }()
    
    // Range tự dừng khi channel closed
    for num := range ch {
        fmt.Println(num)
    }
}
⚠️ Lưu ý: Chỉ sender đóng channel. Gửi vào channel đã đóng sẽ panic!

5. Select Statement

Select cho phép chờ nhiều channels cùng lúc.

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)
    
    go func() { ch1 <- "từ channel 1" }()
    go func() { ch2 <- "từ channel 2" }()
    
    for i := 0; i < 2; i++ {
        select {
        case msg1 := <-ch1:
            fmt.Println(msg1)
        case msg2 := <-ch2:
            fmt.Println(msg2)
        }
    }
}

6. Timeout Với Select

import "time"

func main() {
    ch := make(chan string)
    
    go func() {
        time.Sleep(2 * time.Second)
        ch <- "kết quả"
    }()
    
    select {
    case result := <-ch:
        fmt.Println(result)
    case <-time.After(1 * time.Second):
        fmt.Println("Timeout!")
    }
}

📝 Tóm Tắt