英文:
Reliable way to ensure a Go channel does not block
问题
我正在寻找一种可靠的方法,确保在Go中的空通道不会阻塞我的执行。我必须按特定顺序(一种优先级)迭代通过一些通道,并且一旦找到其中一个通道中有项目,就读取一个项目。
目前,我以类似的方式处理:
if len(myChannel) > 0 {
// 可能存在问题:长度可能已经变为0,使得这个操作变为阻塞
elm := <- myChannel
return elm
}
理论上,这可能导致等待时间过长,而另一个通道可能有一个准备好的项目等待"服务"。
有什么改进的建议吗?我可以在通道中使用互斥锁,但感觉还有更好的解决方案,尽管我不确定是什么。
英文:
I'm looking for a reliable to way to make sure an empty channel in Go does not block my execution. I have to iterate through a number of channels in a particular order (kind of priorities), and once I find one with items in it, read one.
Currently I do something in a similar way:
if len(myChannel) > 0 {
// Possible issue here: length could have changed to 0 making this blocking
elm := <- myChannel
return elm
}
In theory this could result into too-long of waiting, while a different channel might have an item which is ready to be "served".
Any suggestions on how to improve? I could use a mutex in the channel, but it feels like there's a better solution although I'm not sure how.
答案1
得分: 2
有一个reflect.Select
函数可能可以满足你的需求:
package main
import (
"fmt"
"reflect"
"time"
)
func main() {
a, b, c := make(chan int), make(chan int), make(chan int)
go func() {
time.Sleep(2 * time.Second)
a <- 1
}()
go func() {
time.Sleep(time.Second)
b <- 2
}()
go func() {
time.Sleep(3 * time.Second)
c <- 3
}()
for i := 0; i < 3; i++ {
chosen, recv, ok := reflect.Select([]reflect.SelectCase{
reflect.SelectCase{
Dir: reflect.SelectRecv,
Chan: reflect.ValueOf(a),
},
reflect.SelectCase{
Dir: reflect.SelectRecv,
Chan: reflect.ValueOf(b),
},
reflect.SelectCase{
Dir: reflect.SelectRecv,
Chan: reflect.ValueOf(c),
},
})
if ok {
fmt.Printf("从 %d 接收到值 %d\n", chosen, recv.Interface().(int))
}
}
}
英文:
There is a reflect.Select
function that might do what you want:
package main
import (
"fmt"
"reflect"
"time"
)
func main() {
a, b, c := make(chan int), make(chan int), make(chan int)
go func() {
time.Sleep(2 * time.Second)
a <- 1
}()
go func() {
time.Sleep(time.Second)
b <- 2
}()
go func() {
time.Sleep(3 * time.Second)
c <- 3
}()
for i := 0; i < 3; i++ {
chosen, recv, ok := reflect.Select([]reflect.SelectCase{
reflect.SelectCase{
Dir: reflect.SelectRecv,
Chan: reflect.ValueOf(a),
},
reflect.SelectCase{
Dir: reflect.SelectRecv,
Chan: reflect.ValueOf(b),
},
reflect.SelectCase{
Dir: reflect.SelectRecv,
Chan: reflect.ValueOf(c),
},
})
if ok {
fmt.Printf("Got value %d from %d\n", recv.Interface().(int), chosen)
}
}
}
答案2
得分: -1
我不确定这是否真正回答了问题“有没有一种可靠的方法来确保 Go 通道不会阻塞”。在提问者的使用情况中,如果接收操作阻塞了,只要集合中的其他通道不会阻塞,那就没问题,而这也是被接受的解决方案所实现的。这与“确保接收操作不会阻塞”是不同的,我看不到绕过提问者指出的竞态条件基本限制的方法。
英文:
I'm not sure this really answers the question "Is there a reliable way to ensure a Go channel does not block". In the OP's use case, it's OK if a recv blocks /so long as no other channel in the set would not block/, and that's what the accepted solution implements. This is different from "ensure the recv does not block", and I see no way around the fundamental limitation of the race condition OP points out.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论