切換語言為:簡體

Go 語言中 select 和外層 for 的搭配

  • 爱糖宝
  • 2024-05-22
  • 2070
  • 0
  • 0

select語句通常與for迴圈搭配使用,但並不是必須的。

在某些情況下,select可能會直接放在一個獨立的goroutine中,沒有外層的for迴圈。

這通常發生在你知道只會有一次或有限次操作的情況下。

例如,你可能有一個簡單的goroutine,它等待一個特定的channel訊號,然後執行一次操作:

package main

import (
    "fmt"
    "time"
)

func main() {
    interrupt := make(chan struct{})

    go func() {
        // 假設這是接收中斷訊號的goroutine
        <-interrupt
        fmt.Println("Interrupt received, shutting down.")
    }()

    // 等待中斷訊號,無需for迴圈
    select {
    case <-interrupt:
        return
    }
}

在這個例子中,select會阻塞,直到interrupt channel有資料可讀。

一旦接收到資料,select就會結束,程式執行後續的關閉操作。

 

然而,在大多數併發場景中,select與for迴圈結合使用,以便在多個channel之間持續輪詢,直到滿足某種退出條件。

在兩個或更多goroutine之間使用select時,外層的for迴圈通常是用來處理以下情況:

1 持久監聽:select可能會持續等待來自不同goroutine的訊息,這意味著我們需要保持select語句的活性,直到遇到某個特定的退出條件。for迴圈可以保證這一點,直到出現特定的退出條件(例如,所有的channel都被關閉,或者接收到特定的訊號)。

2 非阻塞性檢查:即使沒有資料可讀或可寫,for迴圈也可以配合default子句,用於週期性地檢查某些條件,或者執行其他的非阻塞操作。

3 控制併發行為:透過for迴圈,我們可以控制併發行為,例如限制併發的數量,或者在處理完一批任務後才啟動新的任務。

4 處理不確定的結束條件:在併發環境中,何時結束往往不是預先確定的,for迴圈允許我們持續監控直到滿足結束條件,比如所有的工作都被完成。


下面是一個簡單的例子,展示了select和for迴圈的組合,用於處理兩個channel的資料:

package main

import (
    "fmt"
    "time"
)

func main() {
    intChan1 := make(chan int)
    intChan2 := make(chan int)

    // 啟動兩個goroutines,分別向兩個channel傳送資料
    go func() {
        for i := 1; i <= 5; i++ {
            intChan1 <- i
            time.Sleep(100 * time.Millisecond)
        }
        close(intChan1)
    }()

    go func() {
        for i := 6; i <= 10; i++ {
            intChan2 <- i
            time.Sleep(150 * time.Millisecond)
        }
        close(intChan2)
    }()

    // 使用for迴圈處理兩個channel的資料,直到它們都關閉
    for {
        select {
        case value := <-intChan1:
            fmt.Printf("Received from channel 1: %d\n", value)

        case value := <-intChan2:
            fmt.Printf("Received from channel 2: %d\n", value)

        // 當所有channel都關閉時,for迴圈自然結束
        case <-time.After(1 * time.Second):
            fmt.Println("Both channels closed, exiting.")
            return
        }
    }
}

在這個例子中,for迴圈會一直執行,直到兩個channel都被關閉,或者超時退出。

case <-time.After(1 * time.Second): 是Go中一個常見的用法,它用於在select語句中設定一個超時條件。

這裏的 time.After 函式返回一個channel,當指定的時間過去後,這個channel會發送一個空的結構體【 <-time.After(1 * time.Second) 會從這個channel中接收這個空結構體 】。

在select中,如果有多個case,它會等待可以執行的case,包括這個超時case。


0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.