使选择语句能够同时等待多个通道。

huangapple go评论76阅读模式
英文:

Make the select statement wait for more than one channel at the same time

问题

根据《Go编程语言规范》中的引用:

"select"语句选择一组可能的通信操作中的哪一个将被执行。它看起来类似于"switch"语句,但是case子句都是针对通信操作的。

我如何在case子句中等待多个通道,只有当这些通道都返回时才执行该case子句?

示例

select {
   case <-ch1, <-ch2 ... : //等待ch1和ch2
        // 执行某些操作
   case  ..
}
英文:

To quote from the The Go Programming Language Specification:

> A "select" statement chooses which of a set of possible communications
> will proceed. It looks similar to a "switch" statement but with the
> cases all referring to communication operations.

How can I wait for more than one channel in a case clause, so that only when both channels return the case is executed?

example:

select {

   case &lt;-ch1, &lt;-ch2 ... : //wait for ch1 and ch2 
        // do something 
   case  ..
}

答案1

得分: 6

在相同的选择语句中,没有办法等待多个通道,也没有办法在选择语句中使用"fallthrough",正如文档所描述的:

不过,你可以通过其他方式轻松实现类似的功能。

不使用select:

只有在c1保证返回值的情况下才能使用这种方法,不考虑c2的可用性。

v1 := <-c1
v2 := <-c2

使用循环:

不考虑顺序,但是c1和c2只能触发一次,否则可能会出现问题:

var v1, v2 int
for i := 0; i < 2; i++ {
    select {
    case v1 = <-c1:
    case v2 = <-c2:
    }
}
// 这里v1和v2都被设置了

使用goroutine:

无论哪种方式都可以,但是会失去结果的顺序:

c3 := make(chan int, 2)
go func() { c3 <- (<-c1) }()
go func() { c3 <- (<-c2) }()

first := <-c3
second := <-c3

使用sync.WaitGroup:

无论哪种方式都可以:

var wg sync.WaitGroup
var v1, v2 int
wg.Add(2)
go func() {
    v1 = <-c1
    wg.Done()
}()
go func() {
    v2 = <-c2
    wg.Done()
}()
wg.Wait()
// v1和v2都被设置了

等等,还有其他的方法。最好的方法取决于你想要实现的具体细节。

英文:

There's no way to wait for multiple channels in the same select case, and there's also no way way to "fallthrough" in select cases, as the documentation describes:

You can easily do something like this via other means, though.

Without select:

This only works if c1 is guaranteed to return despite the availability of c2.

v1 := &lt;-c1
v2 := &lt;-c2

With looping:

This works despite the ordering, but c1 and c2 must only fire once, or it might misbehave:

var v1, v2 int
for i := 0; i &lt; 2; i++ {
    select {
    case v1 = &lt;-c1:
    case v2 = &lt;-c2:
    }
}
// both v1 and v2 are set here

With goroutines:

This works either way, but you lose the ordering of results:

c3 := make(chan int, 2)
go func() { c3 &lt;- (&lt;-c1) }()
go func() { c3 &lt;- (&lt;-c2) }()

first := &lt;-c3
second := &lt;-c3

With sync.WaitGroup:

This works either way:

var wg sync.WaitGroup
var v1, v2 int
wg.Add(2)
go func() {
    v1 = &lt;-c1
    wg.Done()
}()
go func() {
    v2 = &lt;-c2
    wg.Done()
}()
wg.Wait()
// v1 and v2 are both set

And so on. There are certainly other ways. The best one depends on the details of what you're trying to achieve.

huangapple
  • 本文由 发表于 2013年9月8日 00:42:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/18675573.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定