Buffered Channel là gì? Ví dụ tạo buffer channel

563

Anh em làm với Golang chắc hẳn đã nghe qua khác niệm Buffered Channel. Vậy Buffered Channel là gì?

Bài viết này sẽ giải thích cho anh em khái niệm Buffered Channel. Deadlock trong Buffered Channel và các ví dụ cụ thể giải thích cách Buffered Channel hoạt động.

Bắt đầu thôi anh em!

1. Buffered Channel là gì?

Tới với định nghĩa:

Channels can be defined as pipes used for Goroutines to communicate. Similar to how water flows from one end to another in a pipe, data can be sent from one end and received from the another end using channels. Channels có thể được định nghĩa là các đường dẫn được sử dụng để Goroutines giao tiếp. Tương tự như cách nước chảy từ đầu này sang đầu kia trong đường ống, dữ liệu có thể nhận vào từ đầu này và chuyển tới đầu kia thông qua channels

Buffered Channel là gì?

Rồi, dứt được một chữ Channel trong Buffered Channel. Kênh này như là cái ống, nhầm như con kênh. Dữ liệu đi vào đầu này sẽ đi ra đầu kia, như nước chảy từ đầu kênh tới cuối kênh.

Còn Buffered (bộ đệm), theo như mặc định trong Golang thì một channel tạo ra sẽ không có Buffered. Kênh không có bộ đệm sẽ chỉ gửi dữ liệu A nếu đầu kia ở channel chấp nhận dữ liệu A. Kênh Buffered Channel sẽ chỉ bị tắc khi bộ đệm full (đầy).

Đó là chiều gửi đi, còn chiều nhận về thì đầu kia của channel sẽ bị chặn dữ liệu nếu bộ đệm trống (buffered is empty).

  So sánh giữa C++ và Golang 
  Xây dựng REST API cơ bản trong Golang

2. Khởi tạo bộ Buffered Channel

Buffered Channel có thể được tạo bằng cách thêm parameter vào hàm make() với kích thước buffer cố định được truyền vào.

Cú pháp :

ch := make(chan type, capacity)           // change định nghĩa kiểu của channel

Trong cú pháp ở trên, capacity là con số cần phải lớn hơn 0, nếu channel đó muốn định nghĩa buffer. Nhưng nếu không có buffer (unbuffered channel) thì để giá trị này là 0. Cứ input cái argument này alf 0 thì auto skip vụ buffer.

Việc làm Golang Hồ Chí Minh hấp dẫn tại TopDev!

3. Ví dụ tạo buffer channel

Anh em cùng ví dụ dưới đây về tạo buffered channel.

package main
 
import (
    "fmt"
)
 
func main() {
 
    // Tạo buffer channel
    // Số lượng là 2.
    ch := make(chan string, 2)
    ch <- "geeksforgeeks"
    ch <- "geeksforgeeks world"
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}

Với đoạn code này, đầu ra sẽ là

geeksforgeeks
geeksforgeeks world

Số lượng buffer được tạo là 2, do đó có thể đưa vào channel 2 chuỗi string, không bị mất mát chuỗi nào và in ra kết quả.

Rồi, ví dụ đầu tiên trơn tru, đầu xuôi đuôi lọt. Cùng tới với ví dụ thứ hai khi bị block do buffer

package main
 
import (
    "fmt"
    "time"
)
 
func write(ch chan int) {
    for i := 0; i < 4; i++ {
        ch <- i
        fmt.Println("successfully wrote", i, "to ch")
    }
    close(ch)
}
func main() {
 
    // Buffer này vẫn có size là 2
    ch := make(chan int, 2)
    go write(ch)
    time.Sleep(2 * time.Second)
    for v := range ch {
        fmt.Println("read value", v, "from ch")
        time.Sleep(2 * time.Second)
 
    }
}

successfully wrote 0 to ch
successfully wrote 1 to ch
read value 0 from ch
successfully wrote 2 to ch
read value 1 from ch
successfully wrote 3 to ch
read value 2 from ch
read value 3 from ch

Anh em chú ý ở vòng for sẽ chạy từ 0 tới 3, có 4 cái đem vào channels, nhưng channel chỉ có maximum là 2. Lúc này Goroutine chỉ ghi được giá trị 0 và 1 vào trong channel ngay lập tức. Sau đó nó block cho tới khi có ít nhất 1 giá trị được đọc từ kênh ch định nghĩa như dưới đây

successfully wrote 0 to ch
successfully wrote 1 to ch

Sau đó, đọc tiếp giá trị rồi sleeps trong 2 giây. Chu kì này cứ lặp đi lặp lại cho đến khi đóng ch. Cho nên mới có khúc tiếp theo được in ra

read value 0 from ch  
successfully wrote 2 to ch

4. Deadlock trong Buffered Channel

Deadlock cũng như khái niệm ở các ngôn ngữ khác, lock lại cho tới chết. Trong Buffered Channel được hiểu là chương trình sẽ có lỗi nghiêm trọng trong quá trình thực thi

package main
 
import (
    "fmt"
)
 
func main() {
    ch := make(chan string, 2)
    ch <- "geeksforgeeks"
    ch <- "hello"
    ch <- "geeks"
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}

Như ví dụ trên đây, quá trình ghi vào channels sẽ bị chặn do kênh đã vượt quá size capacity là 2. Thông báo in ra sẽ là

fatal error: all goroutines are asleep - deadlock!



goroutine 1 [chan send]:

main.main()

    /tmp/sandbox048494311/prog.go:11 +0x8d

5. Tham khảo

Cảm ơn anh em đã đọc bài – Thank you for your time – Happy coding!

Tác giả: Kiên Nguyễn

Xem thêm:

Xem thêm các việc làm Developer hấp dẫn tại TopDev