簡體   English   中英

同時選擇一個發送和接收頻道

[英]Select on a go send and receive channel at the same time

假設我有一個緩沖的發送和無緩沖接收通道:

s := make(chan<- int, 5)
r := make(<-chan int)

是否有可能同時select它們,以便在有任何內容可以讀取時選擇r ,如果它沒有滿,則會選擇s 相當於此的東西,但不使用100%CPU:

for {
    if len(s) < cap(s) {
        // Send something
    }
    if len(r) > 0 {
        // Receive something
    }
}

請注意,我想決定在發送時發送的內容,而不是更早。

編輯

這個問題基本上等同於“我可以阻止直到某個頻道准備發送, 而不發送任何內容嗎?”

您可以使用select執行此操作,但由於要發送的值僅評估一次,如果兩個通道都未就緒,則要發送的值將在發送時變得過時。

因此,添加一個default情況,如果沒有任何通道准備就會執行,你只需要“睡眠”一點,然后再試一次(計算/獲取更新后的新值)。 通過休眠,您將不會消耗CPU資源:

s := make(chan<- int, 5)
r := make(<-chan int)

for {
    v := valueToSend() // Evaluated each time we try to send
    select {
    case s <- v:
        fmt.Println("Sent value:", v)
    case vr := <-r:
        fmt.Println("Received:", vr)
    default: // If none are ready currently, we end up here
        time.Sleep(time.Millisecond * 1)
    }
}

請注意 ,檢查頻道的長度或容量然后發送/接收不被視為一個好的解決方案,因為在您檢查其長度/上限和嘗試發送/接收之間,頻道可能沒有准備好,如下所示:

if len(r) > 0 {
    // r is ready to receive

    // Optional other code here,
    // meanwhile another goroutine might receive the value from r!

    r <-  // If other goroutine received from r, this will block!
}

這是一個簡單的選擇:

select {
case s <- n:
    // Successful send.
case n := <- r:
    // Successful receive. Do something with n.
}

我可以阻止直到某個頻道准備發送,而不發送任何內容嗎?

不是原始的go頻道。 您可能可以設法使用我的頻道庫中的SharedBuffer類型將某些東西拉到一起,但即使這樣也很復雜,它在封面下使用了大量的反射。

https://godoc.org/github.com/eapache/channels#SharedBuffer

您可以發送一個可以計算值的對象,而不是直接發送值。 然后,您可以檢測對象何時發送,然后進行計算。 您可以使用sync.Once確保計算完成一次,並對結果進行門控訪問。 這可以避免使用Sleeps。

像這樣: https//play.golang.org/p/oL2HA2jl91

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM