Quantcast
Channel: 小惡魔 – 電腦技術 – 工作筆記 – AppleBOY
Viewing all articles
Browse latest Browse all 325

Go 語言 Select Multiple Channel 注意事項

$
0
0

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 四大用法


Viewing all articles
Browse latest Browse all 325