检查同时准备好的通道

时间:2015-07-29 17:23:21

标签: go channel petri-net

我想知道go语言是否允许同时检查多个频道

以下是我正在尝试做的一个有点人为的例子。 (实际的原因是看看我是否可以在go中实现petrinets)

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上的值准备就绪时,我不能提交任何一个分支:只有当所有值都准备就绪时。

2 个答案:

答案 0 :(得分:1)

您无法同时在多个频道上进行选择。您可以做的是实现扇入模式,以便从多个渠道合并您的值。

基于代码的粗略示例可能如下所示:

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]
        }
    }
}

答案 1 :(得分: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)
}