为了账号安全,请及时绑定邮箱和手机立即绑定

Go:一个频道有多个听众

Go:一个频道有多个听众

Go
子衿沉夜 2021-09-13 16:51:18
我对 Go 还很陌生,如果主题错误,我很抱歉,但我希望你能理解我的问题。我想通过通道将事件处理到不同的 go 例程。这是一些示例代码type Event struct {    Host string    Command string    Output string}var (    incoming        = make(chan Event))func processEmail(ticker* time.Ticker) {    for {        select {        case t := <-ticker.C:            fmt.Println("Email Tick at", t)        case e := <-incoming:            fmt.Println("EMAIL GOT AN EVENT!")            fmt.Println(e)        }    }}func processPagerDuty(ticker* time.Ticker) {    for {        select {        case t := <-ticker.C:            fmt.Println("Pagerduty Tick at", t)        case e := <-incoming:            fmt.Println("PAGERDUTY GOT AN EVENT!")            fmt.Println(e)        }    }}func main() {    err := gcfg.ReadFileInto(&cfg, "dispatch-api.cfg")    if err != nil {        fmt.Printf("Error loading the config")    }    ticker := time.NewTicker(time.Second * 10)    go processEmail(ticker)    ticker := time.NewTicker(time.Second * 1)    go processPagerDuty(ticker)}func eventAdd(r render.Render, params martini.Params, req *http.Request) {    // create an event now    e := Event{Host: "web01-east.domain.com", Command: "foo", Output: "bar"}    incoming <- e}所以股票代码事件工作只是创建。当我发出一个 API 调用来创建一个事件时,我只是从 processEmail 函数中获得输出。它首先调用的任何 go 例程都将通过通道获取事件。有没有办法让两个函数都得到那个事件?
查看完整描述

2 回答

?
梦里花落0921

TA贡献1772条经验 获得超6个赞

您可以使用扇入和扇出(来自 Rob Pike 的演讲):


package main


func main() {

    // feeders - feeder1, feeder2 and feeder3 are used to fan in

    // data into one channel

    go func() {

        for {

            select {

            case v1 := <-feeder1:

                mainChannel <- v1

            case v2 := <-feeder2:

                mainChannel <- v2

            case v3 := <-feeder3:

                mainChannel <- v3

            }

        }

    }()


    // dispatchers - not actually fan out rather dispatching data

    go func() {

        for {

            v := <-mainChannel


            // use this to prevent leaking goroutines

            // (i.e. when one consumer got stuck)

            done := make(chan bool)


            go func() {

                consumer1 <- v

                done <- true

            }()

            go func() {

                consumer2 <- v

                done <- true

            }()

            go func() {

                consumer3 <- v

                done <- true

            }()


            <-done

            <-done

            <-done

        }

    }()


    // or fan out (when processing the data by just one consumer is enough)

    go func() {

        for {

            v := <-mainChannel

            select {

            case consumer1 <- v:

            case consumer2 <- v:

            case consumer3 <- v:

            }

        }

    }()


    // consumers(your logic)

    go func() { <-consumer1 /* using the value */ }()

    go func() { <-consumer2 /* using the value */ }()

    go func() { <-consumer3 /* using the value */ }()

}


type payload int


var (

    feeder1 = make(chan payload)

    feeder2 = make(chan payload)

    feeder3 = make(chan payload)


    mainChannel = make(chan payload)


    consumer1 = make(chan payload)

    consumer2 = make(chan payload)

    consumer3 = make(chan payload)

)



查看完整回答
反对 回复 2021-09-13
?
阿晨1998

TA贡献2037条经验 获得超6个赞

通道是一种点对点通信方法,而不是广播通信方法,所以不,如果不做一些特殊的事情,您无法同时获得两个函数来获取事件。

您可以为两个 goroutine 设置单独的通道并将消息发送到每个通道。这可能是最简单的解决方案。

或者,您可以让一个 goroutine 向下一个发出信号。

据我所知,Go 有两种机制来进行广播信令。一是关闭通道。但这只能工作一次。

另一种是使用sync.Cond锁。这些使用起来比较棘手,但可以让您有多个 goroutines 被单个事件唤醒。

如果我是你,我会选择第一个选项,将事件发送到两个不同的频道。这似乎很好地映射了问题。


查看完整回答
反对 回复 2021-09-13
  • 2 回答
  • 0 关注
  • 182 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信