英文:
Checking for simultaneous channels ready in go
问题
我想知道Go语言是否允许同时检查多个通道是否准备就绪。
这是一个有点牵强的例子,展示了我想要做的事情(实际原因是看看我是否可以在Go中本地实现Petri网)。
package main
import "fmt"
func mynet(a, b, c, d <-chan int, res chan<- int) {
for {
select {
case v1, v2 := <-a, <-b:
res <- v1+v2
case v1, v2 := <-c, <-d:
res <- v1-v2
}
}
}
func main() {
a := make(chan int)
b := make(chan int)
c := make(chan int)
d := make(chan int)
res := make(chan int, 10)
go mynet(a, b, c, d, res)
a <- 5
c <- 5
d <- 7
b <- 7
fmt.Println(<-res)
fmt.Println(<-res)
}
这段代码无法编译。可以通过只检查一个通道来使其编译通过,但是如果该通道准备就绪而另一个通道没有准备就绪,就会产生死锁。
package main
import "fmt"
func mynet(a, b, c, d <-chan int, res chan<- int) {
for {
select {
case v1 := <-a:
v2 := <-b
res <- v1+v2
case v1 := <-c:
v2 := <-d
res <- v1-v2
}
}
}
func main() {
a := make(chan int)
b := make(chan int)
c := make(chan int)
d := make(chan int)
res := make(chan int, 10)
go mynet(a, b, c, d, res)
a <- 5
c <- 5
d <- 7
//a <- 5
b <- 7
fmt.Println(<-res)
fmt.Println(<-res)
}
在一般情况下,我可能会有多个等待同一个通道的情况,例如:
case v1, v2 := <-a, <-b:
...
case v1, v2 := <-a, <-c:
...
因此,当通道a上的一个值准备就绪时,我不能确定选择哪个分支,只有当所有值都准备就绪时才能确定。
英文:
I would like to know if the go language allows checking for multiple channels being ready at the same time.
Here is a somewhat contrived example of what I'm trying to do. (The actual reason is to see if I can implement petrinets natively in go)
package main
import "fmt"
func mynet(a, b, c, d <-chan int, res chan<- int) {
for {
select {
case v1, v2 := <-a, <-b:
res <- v1+v2
case v1, v2 := <-c, <-d:
res <- v1-v2
}
}
}
func main() {
a := make(chan int)
b := make(chan int)
c := make(chan int)
d := make(chan int)
res := make(chan int, 10)
go mynet(a, b, c, d, res)
a <- 5
c <- 5
d <- 7
b <- 7
fmt.Println(<-res)
fmt.Println(<-res)
}
This doesn't compile as shown. It can be made to compile by only checking one channel, but then it can trivially deadlock if that channel is ready but the other one is not.
package main
import "fmt"
func mynet(a, b, c, d <-chan int, res chan<- int) {
for {
select {
case v1 := <-a:
v2 := <-b
res <- v1+v2
case v1 := <-c:
v2 := <-d
res <- v1-v2
}
}
}
func main() {
a := make(chan int)
b := make(chan int)
c := make(chan int)
d := make(chan int)
res := make(chan int, 10)
go mynet(a, b, c, d, res)
a <- 5
c <- 5
d <- 7
//a <- 5
b <- 7
fmt.Println(<-res)
fmt.Println(<-res)
}
In the general case, I might have multiple cases waiting on the same channel, e.g.
case v1, v2 := <-a, <-b:
...
case v1, v2 := <-a, <-c:
...
so I can't commit to either branch when a value is ready on channel a: only when all values are ready.
答案1
得分: 2
你无法同时选择多个通道。你可以实现一个扇入模式来从多个通道中汇总值。
根据你的代码,一个简单的示例可能如下所示:
func collect(ret chan []int, chans ...<-chan int) {
ints := make([]int, len(chans))
for i, c := range chans {
ints[i] = <-c
}
ret <- ints
}
func mynet(a, b, c, d <-chan int, res chan<- int) {
set1 := make(chan []int)
set2 := make(chan []int)
go collect(set1, a, b)
go collect(set2, c, d)
for {
select {
case vs := <-set1:
res <- vs[0] + vs[1]
case vs := <-set2:
res <- vs[0] + vs[1]
}
}
}
英文:
You can't select on multiple channels simultaneously. What you can do is implement a fan-in pattern for coalescing your values from multiple channels.
A rough example based on your code might look like:
func collect(ret chan []int, chans ...<-chan int) {
ints := make([]int, len(chans))
for i, c := range chans {
ints[i] = <-c
}
ret <- ints
}
func mynet(a, b, c, d <-chan int, res chan<- int) {
set1 := make(chan []int)
set2 := make(chan []int)
go collect(set1, a, b)
go collect(set2, c, d)
for {
select {
case vs := <-set1:
res <- vs[0] + vs[1]
case vs := <-set2:
res <- vs[0] + vs[1]
}
}
}
答案2
得分: 0
两个不同的配对所累积的个别通道可能会起作用:
package main
import "fmt"
func mynetPlus(a, b <-chan int, res chan<- int) {
for {
select {
case v1 := <-a:
v2 := <-b
res <- v1 + v2
case v2 := <-b:
v1 := <-a
res <- v1 + v2
}
}
}
func mynetMinus(c, d <-chan int, res chan<- int) {
for {
select {
case v1 := <-c:
v2 := <-d
res <- v1 + v2
case v2 := <-d:
v1 := <-c
res <- v1 + v2
}
}
}
func main() {
a := make(chan int)
b := make(chan int)
c := make(chan int)
d := make(chan int)
res := make(chan int, 10)
go mynetPlus(a, b, res)
go mynetMinus(c, d, res)
a <- 5
c <- 5
d <- 7
//a <- 5
b <- 7
fmt.Println(<-res)
fmt.Println(<-res)
}
希望对你有帮助!
英文:
Individual channels for the two different pairs that you are accumulating may work:
package main
import "fmt"
func mynetPlus(a, b <-chan int, res chan<- int) {
for {
select {
case v1 := <-a:
v2 := <-b
res <- v1 + v2
case v2 := <-b:
v1 := <-a
res <- v1 + v2
}
}
}
func mynetMinus(c, d <-chan int, res chan<- int) {
for {
select {
case v1 := <-c:
v2 := <-d
res <- v1 + v2
case v2 := <-d:
v1 := <-c
res <- v1 + v2
}
}
}
func main() {
a := make(chan int)
b := make(chan int)
c := make(chan int)
d := make(chan int)
res := make(chan int, 10)
go mynetPlus(a, b, res)
go mynetMinus(c, d, res)
a <- 5
c <- 5
d <- 7
//a <- 5
b <- 7
fmt.Println(<-res)
fmt.Println(<-res)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论