溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

go語言中怎么使用select

發(fā)布時間:2022-05-13 13:48:23 來源:億速云 閱讀:204 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“go語言中怎么使用select”的相關(guān)知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強(qiáng),希望這篇“go語言中怎么使用select”文章能幫助大家解決問題。

在golang語言中,select語句 就是用來監(jiān)聽和channel有關(guān)的IO操作,當(dāng)IO操作發(fā)生時,觸發(fā)相應(yīng)的case動作。

有了 select語句,可以實現(xiàn) main主線程 與 goroutine線程 之間的互動。

1.基本語法

select {
    case <-ch2 :     // 檢測有沒有數(shù)據(jù)可讀
        // 一旦成功讀取到數(shù)據(jù),則進(jìn)行該case處理語句
    case ch3 <- 1 :  // 檢測有沒有數(shù)據(jù)可寫
        // 一旦成功向ch3寫入數(shù)據(jù),則進(jìn)行該case處理語句
    default:
        // 如果以上都沒有符合條件,那么進(jìn)入default處理流程
}

注意事項

  • select語句 只能用于channel信道的IO操作,每個case都必須是一個信道。

  • 如果不設(shè)置 default條件,當(dāng)沒有IO操作發(fā)生時,select語句就會一直阻塞;

  • 如果有一個或多個IO操作發(fā)生時,Go運行時會隨機(jī)選擇一個case執(zhí)行,但此時將無法保證執(zhí)行順序;

  • 對于case語句,如果存在信道值為nil的讀寫操作,則該分支將被忽略,可以理解為相當(dāng)于從select語句中刪除了這個case;

  • 對于空的 select語句,會引起死鎖;

  • 對于在 for中的select語句,不能添加 default,否則會引起cpu占用過高的問題;

(1)多個IO操作發(fā)生時,case語句是隨機(jī)執(zhí)行的

func main()  {
    ch2 := make(chan int, 1)   // 創(chuàng)建 一個長度帶緩沖的整型通道
    ch2 <- 1                   // 向通道中寫入數(shù)據(jù)

    ch3 := make(chan int, 1)
    ch3 <- 2

    select {
        case <- ch2:
            fmt.Println("ch2 read")
        case <- ch3:
            fmt.Println("ch3 read")
    }
}

多次執(zhí)行后,會隨機(jī)打印 “ch2 read” 或 “ch3 read”

(2)空select語句

func main()  {
    select {
    
    }
}

執(zhí)行后,引發(fā)死鎖,打印如下:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [select (no cases)]:
main.main()
        xxx/test.go:4 +0x27
exit status 2

(3)for中的select 引起CPU資源消耗過高

func main()  {
    quit := make(chan bool)
    go func() {
        for {
            select {
            case <-quit:
                fmt.Println("quit")
                // 使用 return 就會退出整個goroutine線程;如果使用 break,程序仍然在for循環(huán)中執(zhí)行
                return
            default:
                fmt.Println("default")
            }
        }
    }()

    time.Sleep(3 * time.Second)
    quit <- true          // 主線程在3秒后,向quit信道寫入數(shù)據(jù)
    
    time.Sleep(2 * time.Second)
    fmt.Println("main")
}

在for{}的select語句中使用了 default后,線程就會無限執(zhí)行default條件,直到quit信道中讀到數(shù)據(jù),否則會一直在一個死循環(huán)中運行,從而導(dǎo)致占滿整個CPU資源。

在 for{}的select語句中,不建議使用 default條件。

2.select語句的實際應(yīng)用

(1)實現(xiàn) main主線程與 goroutine線程 之間的交互、通信

// 通過控制臺輸入 "bye", 來控制main函數(shù)結(jié)束運行
func main()  {
    quit := make(chan bool)
    ch := make(chan string)

    go func() {
        for {
            select {
            case name := <-ch:
                fmt.Printf("from main msg: [%v]\n", name)
                if name == "bye" {
                    quit <- true
                } else {
                    quit <- false
                }
            }
        }
    }()

    for {
        // 控制臺輸入
        fmt.Print("please input string: ")
        scanner := bufio.NewScanner(os.Stdin)
        scanner.Scan()
        ch <- scanner.Text()

        isOver := <- quit
        if isOver {
            break
        }
    }
    fmt.Println("main over")
}

運行:

from main msg: [aaa]
please input string: bbb
from main msg: [bbb]
please input string: bye
from main msg: [bye]
main over

(2)超時實現(xiàn)

func main()  {
    quit := make(chan bool)
    ch := make(chan int)

    go func() {
        for {
            select {
            case num := <- ch:
                fmt.Println("num = ", num)
            case <- time.After(5 * time.Second):
                fmt.Println("超時")
                quit <- true
            }
        }
    }()

    for i := 0; i < 2; i++ {
        ch <- i
        time.Sleep(time.Second)
    }
    <- quit                   // 等待超時后, 結(jié)束 main主線程
    fmt.Println("程序結(jié)束")
}

關(guān)于“go語言中怎么使用select”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識,可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI