Trong ngôn ngữ Go, câu lệnh select giống như câu lệnh switch, nhưng trong câu lệnh select, câu lệnh case đề cập đến giao tiếp, tức là hoạt động gửi hoặc nhận trên kênh.
Cú pháp:
select{
case SendOrReceive1: // Lệnh
case SendOrReceive2: // Lệnh
case SendOrReceive3: // Lệnh
.......
default: // Lệnh
Trong bài viết này, chúng ta sẽ tìm hiểu cách sử dụng trường hợp mặc định để tránh rơi vào bế tắc - deadlock. Nhưng trước tiên, chúng ta sẽ tìm hiểu deadlock case khi dùng lệnh select của Golang là gì?
Những điều cần biết về deadlock case trong Golang
Deadlock: Khi bạn cố gắng đọc hoặc ghi dữ liệu từ kênh nhưng kênh không có giá trị. Vì vậy, nó chặn việc thực thi hiện tại của goroutine và chuyển quyền điều khiển cho các goroutine khác, nhưng nếu không có goroutine nào khác khả dụng hoặc các goroutine khác đang nghỉ do tình huống này, chương trình sẽ bị sập. Hiện tượng này được gọi là deadlock. Như được hiển thị trong ví dụ bên dưới:
Ví dụ:
// Chương trình Go minh hoạc
// cách deadlock phát sinh
package main
// Hàm chính
func main() {
// Tạo một kênh
// Deadlock phát sinh bởi
// không có goroutine đang viết
// vào kênh này, vì thế
// lệnh select đã bị khóa mãi mãi
c := make(chan int)
select {
case <-c:
}
}
Kết quả:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
Để tránh tình huống này, chúng ta sử dụng trường hợp mặc định trong câu lệnh select. Hay nói cách khác, khi deadlock xảy ra trong chương trình, thì default case của câu lệnh select được thực thi để tránh deadlock. Như trong ví dụ dưới đây, chúng ta sử dụng trường hợp mặc định trong câu lệnh select để tránh deadlock.
Ví dụ:
// Chương trình Go minh họa cách giải quyết
// vấn đề deadlock bằng case mặc định
package main
import "fmt"
// Hàm chính
func main() {
// Tạo 1 kênh
c := make(chan int)
select {
case <-c:
default:
fmt.Println("!.. Default case..!")
}
}
Kết quả:
!.. Default case..!
Bạn cũng được phép sử dụng trường hợp mặc định khi câu lệnh select chỉ có kênh nil. Như được hiển thị trong ví dụ bên dưới, kênh c là nil, do đó trường hợp mặc định được thực thi nếu trường hợp mặc định ở đây không khả dụng, thì chương trình sẽ bị chặn mãi mãi và deadlock phát sinh.
Ví dụ:
// Chương trình Go minh họa
// chạy case mặc định
package main
import "fmt"
// Hàm chính
func main() {
// Tạo một kênh
var c chan int
select {
case x1 := <-c:
fmt.Println("Value: ", x1)
default:
fmt.Println("Default case..!")
}
}
Kết quả:
Default case..!