Golang select语句中的死锁和默认案例

在Go语言中,选择语句就像switch语句一样,但在选择语句中,case语句指的是通信,即在通道上的发送或接收操作。

语法

select{

case SendOrReceive1: // Statement
case SendOrReceive2: // Statement
case SendOrReceive3: // Statement
.......
default: // Statement

在这篇文章中,我们学习如何利用默认情况来避免死锁。但首先,我们要学习什么是死锁?

死锁: 当你试图从通道中读取或写入数据,但通道中没有值。因此,它阻止了当前goroutine的执行,并将控制权传递给其他goroutine,但如果没有其他goroutine可用或其他goroutine处于睡眠状态,由于这种情况程序将崩溃。这种现象被称为死锁。如下面的例子所示。

例子

// Go program to illustrate
// how deadlock arises
package main
  
// Main function
func main() {
  
    // Creating a channel
    // Here  deadlock arises because
    // no goroutine is writing
    // to this channel so, the select 
    // statement has been blocked forever
    c := make(chan int)
    select {
    case <-c:
    }
}

输出

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()

为了避免这种情况,我们在选择语句中使用一个默认情况。换句话说,当程序中出现死锁时,就执行选择语句的默认情况,以避免死锁。如下面的例子所示,我们在选择语句中使用默认情况来避免死锁。

例子

// Go program to illustrate how to resolve
// the deadlock problem using the default case
package main
  
import "fmt"
  
// Main function
func main() {
  
    // Creating a channel
    c := make(chan int)
    select {
    case <-c:
    default:
        fmt.Println("!.. Default case..!")
    }
}

输出

!.. Default case..!

当select语句中只有nil通道时,你也可以使用默认情况。如下面的例子所示,通道c是nil,所以默认情况下执行,如果这里的默认情况不可用,那么程序将永远被阻塞,产生死锁。

例子

// Go program to illustrate
// the execution of default case
package main
  
import "fmt"
  
// Main function
func main() {
  
    // Creating a channel
    var c chan int
  
    select {
    case x1 := <-c:
        fmt.Println("Value: ", x1)
    default:
        fmt.Println("Default case..!")
    }
}

输出

Default case..!