Select 在被阻止的呼叫和频道上

Select on blocked call and channel

我很确定我以前看到过关于这个的问题,但现在找不到了。

本质上,我想 select 在被阻止的呼叫和频道上。

我知道我可以将阻塞的调用推送到 goroutine 中并通过通道等待结果,但感觉这是错误的解决方案。

有没有我想念的惯用方式来写这个?

最理想的情况是:

select {
case a <- c:
  ...
case ans := connection.Read():
  ...
}

如果你有一个通道和一个你想要的函数 select,使用 goroutine 和一个通道是惯用的解决方案。请注意,如果从通道接收到一个值,那不会影响该功能,它会继续 运行。您可以使用 context.Context 来表示不再需要它的结果,它可能会提前终止。

如果允许重构,则可以“使”函数在同一通道上发送,因此您只需要从单个通道接收。

另一个重构想法是让函数监视同一个通道并尽早 return,因此您可以只进行一次调用而无需 select

注意,如果你需要在很多地方这样做,你可以创建一个辅助函数来异步启动它:

func launch(f func()) <-chan struct{} {
    done := make(chan struct{})
    go func() {
        defer close(done)
        f()
    }()
    return done
}

示例函数:

func test() {
    time.Sleep(time.Second)
}

然后使用它:

select {
case a := <-c:
    fmt.Println("received from channel:", a)
case <-launch(test):
    fmt.Println("test() finished")

}

Go Playground 上试用。