5

Go 語言 Select Multiple Channel 注意事項

 3 years ago
source link: https://blog.wu-boy.com/2020/10/select-multiple-channel-in-golang/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Go 語言 Select Multiple Channel 注意事項

golang logo

相信大家都知道 Select 可以用來處理多個 Channel,但是大家有沒有想過一個情境,如果是 for 搭配 select 時,肯定會用一個 Timer 或 context 來處理 Timeout 或手動 Cancel,假設如果跟其他 Channel 同時到達時,官方說法是 Select 會隨機選擇一個狀況來執行,如果並非選到我們所要的 case 那就會造成情境或流程上的錯誤,而本影片就是講解該如何解決此問題,請大家務必詳細了解業務的需求,來決定程式碼架構該如何寫。

00:00 簡介程式碼
01:03 NewTicker 跟 Channel 同時執行狀況
03:29 解決方案一以及限制 (多個 Channel 就不適用了)
05:06 多個一樣的 case 提供優先權
07:28 用 Kubernetes Client 案例來講解

其中 Kubernetes Client 範例來自這邊

如果對於課程內容有興趣,可以參考底下課程。

如果需要搭配購買請直接透過 FB 聯絡我,直接匯款(價格再減 100

多個 Channle 同時讀寫

底下直接用範例解釋 (此範例來源自『go里面select-case和time.Ticker的使用注意事项』),也可以參考整個 FB 討論串

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int, 1024)
    go func(ch chan int) {
        for {
            if v, ok := <-ch; ok {
                fmt.Printf("val:%d\n", v)
            }
        }
    }(ch)

    tick := time.NewTicker(1 * time.Second)
    for i := 0; i < 30; i++ {
        select {
        // how to make sure all number in ch channel?
        case ch <- i:
        case <-tick.C:
            fmt.Printf("%d: case <-tick.C\n", i)
        }

        time.Sleep(200 * time.Millisecond)
    }
    close(ch)
    tick.Stop()
}

大家可以看到上面開始有個 goroutine 用來接收 ch channel 的內容,接著看看下面的 for 迴圈內有個 select 用來接受或寫入 Channel,但是這時候會發生一個問題,當 i = 5 時,是有機率會兩個 case 同時發生,這時候按照 Go 語言官方範例提到內容

A select blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready.

是會隨機的方式選取一個,所以會發現有機率會少接收到 ch 值,所以底下有幾種方式可以解決此問題。也就是要確保 ch 可以接收到 0 ~ 29 數字。其中第一個做法就是將 ch <- i 加入到 tick.C 內

    for i := 0; i < 30; i++ {
        select {
        case ch <- i:
        case <-tick.C:
            fmt.Printf("%d: case <-tick.C\n", i)
            ch <- i
        }

        time.Sleep(200 * time.Millisecond)
    }

第二種作法就是透過 select default 方式不要讓程式 blocking

    for i := 0; i < 30; i++ {
        ch <- i
        select {
        case <-tick.C:
            fmt.Printf("%d: case <-tick.C\n", i)
        default:
        }

        time.Sleep(200 * time.Millisecond)
    }

上述這兩種方式都可以,只是真的要依照團隊業務邏輯來決定怎樣修改才是正確的。這概念已經有在去年 (2019) 的 Blog 講過,如果要再多了解 Select 語法,可以參考之前寫的文章『Go 語言使用 Select 四大用法

265bcbb56e831266de7a9f9281aab57a?s=49&r=gAuthor appleboyPosted on 2020/10/122020/10/18Categories GolangTags channel, golang, golang channel


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK