[英]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
類型將某些東西拉到一起,但即使這樣也很復雜,它在封面下使用了大量的反射。
您可以發送一個可以計算值的對象,而不是直接發送值。 然后,您可以檢測對象何時發送,然后進行計算。 您可以使用sync.Once確保計算完成一次,並對結果進行門控訪問。 這可以避免使用Sleeps。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.