英文:
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 <-ch1, <-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 := <-c1
v2 := <-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 < 2; i++ {
select {
case v1 = <-c1:
case v2 = <-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 <- (<-c1) }()
go func() { c3 <- (<-c2) }()
first := <-c3
second := <-c3
With sync.WaitGroup:
This works either way:
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 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论