博客 / 詳情

返回

Select多路複用

在某些場景下我們需要同時從多個通道接收數據。通道在接收數據時,如果沒有數據可以接收將會發生阻塞,而select就可以同時監聽一個或多個channel,直到其中一個channel準備好。

select的使用類似於switch語句,它有一系列case分支和一個默認的分支。每個case會對應一個通道的通信(接收或發送)過程。select會一直等待,直到某個case的通信操作完成時,就會執行case分支對應的語句。具體格式如下:

    select {
    case <-chan1:
       // 如果chan1成功讀到數據,則進行該case處理語句
    case chan2 <- 1:
       // 如果成功向chan2寫入數據,則進行該case處理語句
    default:
       // 如果上面都沒有成功,則進入default處理流程
    }
package main

import (
    "fmt"
    "time"
)

func test1(ch chan string) {
    time.Sleep(time.Second * 1)
    ch <- "test1"
}
func test2(ch chan string) {
    time.Sleep(time.Second * 2)
    ch <- "test2"
}

func main() {
    // 2個管道
    output1 := make(chan string)
    output2 := make(chan string)
    // 跑2個子協程,寫數據
    go test1(output1)
    go test2(output2)
    for {
        // 用select監控
        select {
        case s1 := <-output1:
            fmt.Println("s1=", s1)
        case s2 := <-output2:
            fmt.Println("s2=", s2)
        default:
            ticker := time.NewTicker(1 * time.Second)
            fmt.Printf("%v\n", <-ticker.C)
        }
    }
}

判斷通道是否已經存滿

package main

import (
    "fmt"
    "time"
)

// 判斷管道有沒有存滿
func main() {
    // 創建管道
    output1 := make(chan string, 1)
    // 子協程寫數據
    go write(output1)
    // 取數據
    for s := range output1 {
        fmt.Println("res:", s)
        time.Sleep(time.Second)
    }
}

func write(ch chan string) {
    for {
        select {
        // 寫數據
        case ch <- "hello":
            fmt.Println("write hello")
        default:
            fmt.Println("channel full")
        }
        time.Sleep(time.Millisecond * 500)
    }
}
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.