- vừa được xem lúc

[Golang] Channel trong golang và use case - part I

0 0 26

Người đăng: Phượng Sồ

Theo Viblo Asia

Mở đầu

  • Lập trình concurrency luôn là một thứ làm các gopher tự hào so với các ngôn ngữ khác. Các ngôn ngữ phổ biến như JAVA, C# implements concurrency bằng việc sử dụng thread, còn GO thì sử dụng 2 built-in features - goroutine và channel. Chúng giúp việc tiếp cận hay quản lý các công việc đồng thời trở nên dể dàng và đỡ tốn chi phí hơn rất nhiều.
  • Goroutines bản chất là các hàm (function) hay method được thực thi một các độc lập và đồng thời nhưng vẫn có thể kết nối với nhau. Và channel chính là kênh giao tiếp giữa các goroutine đó.

Channel

  • Channel cung cấp một cách để các goroutines giao tiếp với nhau và đồng bộ hóa việc thực thi của chúng.
  • Nói đến giao tiếp, thì phải có 2 chiều - chiều gửi và chiều nhận. Channel cũng như thế, goroutine hoàn toàn có thể gửi đến dữ liệu đến channel và lấy dữ liệu từ channel.
  • Channel được phân thành 2 loại: buffer channel and unbuffered channel. Đối với unbuffer channel, khi một goroutine A gửi dữ liệu đến thì nó sẽ tiến hành block goroutine A lại cho đến khi có go routine bất kỳ đến lấy dữ liệu. Và ngược lại, buffer channel sẽ nhẹ nhàng hơn, không có yêu cầu khắt khe gì cả, nó được mang trong mình một sức chứa(capicity) nhất định và không cần bất kỳ receiver goroutine nào. Tuy nhiên, khi capicity đến mức giới hạn thì nó cũng cần goroutines đến lấy dữ liệu ra.

Play with unbuffered channel

  • From main goroutine, gửi dữ liệu đến channel without receiver goroutine
    func main() { /* Without receiver goroutine from main goroutine */ chanelAtMainRoutine := make(chan int) chanelAtMainRoutine <- 5
    }
    result: fatal error: all goroutines are asleep - deadlock!
    
    Chương trình bị crash(terminated) và thông báo lỗi bởi vì main goroutine bị block trong một khoảng thời gian.
  • From anonymous goroutine, gửi dữ liệu đến channel without receiver goroutine
    func main() { /* Without receiver from anonymous goroutine */ chanelAtMainRoutine := make(chan int) go func() { chanelAtMainRoutine <- 5 }() fmt.Println("Completing ...")
    }
    result: Completing ...
    
    Việc chương trình ko bị terminated or crash ở đây là hoàn toàn chính xác mặc dù channel vẫn chưa có một goroutine nào đến lấy dữ liệu. Channel thực chất chỉ block anonymous goroutine và main goroutine vẫn tiếp chạy và in ra kết quả "completing ...."
  • From main goroutine, gửi dữ liệu đến channel with receiver goroutine
    func main() { /* With receiver from main goroutine */ chanelAtMainRoutine := make(chan int) go func() { fmt.Println("Start getting value from channel ...") <-chanelAtMainRoutine fmt.Println("Complete getting value from channel ...") }() chanelAtMainRoutine <- 5 fmt.Println("Completing ...")
    }
    result: Start getting value from channel ... Complete getting value from channel ... Completing ...
    
    Recevier goroutine xuất hiện và main goroutine ko bị lock nữa. Tuy nhiên, nếu trong quá trình chạy func main nhiều lần ta sẽ thấy dòng "Complete getting value from channel ..." sẽ có lúc ko được in ra màn hình console bởi vì ngay tại thời điểm câu lệnh "<-chanelAtMainRoutine" được thực thi xong, thưc chất golang runtime schedule switch sang main goroutine và nếu việc chuyển đổi này đủ nhanh, sẽ ko có câu lệnh nào kịp thực thi ngay sau đó. Để kiểm chứng điều này, tôi sẽ tiến hành sleep một giây tai recevier goroutine.
    Increase time at recevier goroutine
    func main() { /* Increase time at receiver goroutine */ chanelAtMainRoutine := make(chan int) go doBigJob(chanelAtMainRoutine) chanelAtMainRoutine <- 5 fmt.Println("Completing ...")
    } func doBigJob(ch <-chan int) { fmt.Println("Start getting value from channel ...") <-ch time.Sleep(time.Second * 1) fmt.Println("Complete getting value from channel ...")
    }
    result: Start getting value from channel ... // Cannot see "Complete getting value ..." any more Completing ...
    

Tạm kết

  • Về nguyên lý , unbuffered channel hoạt động giống như môn bóng bàn. Khi bóng giao đi thì phải có người đỡ. Ở ví dụ trên chúng ta có thể chuyển sang dùng buffer channel , để câu lệnh fmt.Println("Complete getting value from channel ...") được thực thi ngay khi dữ liệu của channel được lấy ra.
  • Source code
  • Hẹn các bạn đón xem phần tiếp theo. Chúng ta sẽ đi tìm hiểu thêm về buffered channel và các usecase của nó.

Bình luận

Bài viết tương tự

- vừa được xem lúc

gRPC - Nó là gì và có nên sử dụng hay không?

Nhân một ngày rảnh rỗi, mình ngồi đọc lại RPC cũng như gRPC viết lại để nhớ lâu hơn. Vấn đề là gì và tại sao cần nó .

0 0 131

- vừa được xem lúc

Embedded Template in Go

Getting Start. Part of developing a web application usually revolves around working with HTML as user interface.

0 0 56

- vừa được xem lúc

Tạo Resful API đơn giản với Echo framework và MySQL

1. Giới thiệu.

0 0 60

- vừa được xem lúc

Sử dụng goquery trong golang để crawler thông tin các website Việt Nam bị deface trên mirror-h.org

. Trong bài viết này, mình sẽ cùng mọi người khám phá một package thu thập dữ liệu có tên là goquery của golang. Mục tiêu chính của chương trình crawler này sẽ là lấy thông tin các website Việt Nam bị deface (là tấn công, phá hoại website, làm thay đổi giao diện hiển thị của một trang web, khi người

0 0 237

- vừa được xem lúc

Tạo ứng dụng craw dữ liệu bing với Golang, Mysql driver

Chào mọi người . Lâu lâu ta lại gặp nhau 1 lần, để tiếp tục series chia sẻ kiến thức về tech, hôm nay mình sẽ tìm hiểu và chia sẻ về 1 ngôn ngữ đang khá hot trong cộng đồng IT đó là Golang.

0 0 75

- vừa được xem lúc

Golang: Rest api and routing using MUX

Routing with MUX. Let's create a simple CRUD api for a blog site. # All . GET articles/ .

0 0 54