通道未接收数据或出现死块

我有以下代码:


//main.go

package main


import (

    "edriven/events"

    "fmt"

    "math"

    "time"

)


func main() {

    fmt.Println("Starting")

    events.Wg.Add(1)

    go events.User.Trigger("new", "Hasan")

    events.Wg.Add(1)

    go events.User.Trigger("name", []any{"Hasan", "Ali"})

    events.Wg.Add(1)

    go events.User.Trigger("new", "Ali")


    //for x := range <-events.Publish {

    //  fmt.Println(x)

    //}


    for {

        select {

        case x := <-events.Publish:

            fmt.Println(x)

        default:

            fmt.Println("waiting for data ...")

            time.Sleep((time.Duration(math.MaxInt64)))

        }

    }

}


//events/user.go

package events


import "fmt"


var User Events


func init() {

    User.register("new", func(payload ...any) {

        fmt.Println(payload[0])

        //message := make(map[string]string)

        //message["new"] = "done new"

        Publish <- "{'new':'done'}"

        Wg.Done()


    })


    User.register("name", func(payload ...any) {

        for index, person := range payload {

            fmt.Println(person, index)

        }

        //message := make(map[string]string)

        //message["name"] = "done name"

        Publish <- "{'name':'done'}" //message

        Wg.Done()

    })

}


//events/setup.go

package events


import "sync"


var Wg sync.WaitGroup

var Publish chan string


type Event struct {

    Name   string

    Action func(...any) // <-chan string // func(...any) ([]any, error)


}


type Events struct {

    handlers []Event

}


func (e *Events) register(name string, action func(...any)) {

    e.handlers = append(e.handlers, Event{

        Name:   name,

        Action: action,

    })

}


func (e *Events) Trigger(name string, payload ...any) {

    for _, event := range e.handlers {

        if event.Name == name {

            event.Action(payload)

        }

    }

}

我得到的输出如下,没有通过通道交换任何东西

http://img4.mukewang.com/63b3c2ec00012c9f06390241.jpg

猛跑小猪
浏览 107回答 1
1回答

九州编程

这段代码有问题for {&nbsp; &nbsp; select {&nbsp; &nbsp; case x := <- events.Publish:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(x)&nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("waiting for data ...")&nbsp; &nbsp; &nbsp; &nbsp; time.Sleep((time.Duration(math.MaxInt64)))&nbsp; &nbsp; }}当select被调用并假设Publish通道仍然为空时,默认情况将运行并使用该time.Sleep语句永远阻塞主循环。因此,即使Publish通道从另一个 go-routine 接收数据,主 go-routine 仍然停留在该 Sleep 语句上。任何时候你想将定时等待与通道事件结合起来,你可以这样做:timerChannel := time.NewTimer(duration)select {case <-timerChannel.C:&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // time out&nbsp; &nbsp; }case x := <-events.Publish:&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; fmt.println(x)&nbsp; &nbsp; }}但是由于您的意图似乎只是阻止main退出,所以它更简单:for {&nbsp; &nbsp; x := <- events.Publish:&nbsp; // blocks until Publish channel has data&nbsp; &nbsp; fmt.Println(x)}但是正如你所说的那样,这会导致僵局,因为在你的三个 go-routines 退出后,就没有什么可做的了。快速解决:func main() {&nbsp; &nbsp; fmt.Println("Starting")&nbsp; &nbsp; events.Wg.Add(1)&nbsp; &nbsp; go events.User.Trigger("new", "Hasan")&nbsp; &nbsp; events.Wg.Add(1)&nbsp; &nbsp; go events.User.Trigger("name", []any{"Hasan", "Ali"})&nbsp; &nbsp; events.Wg.Add(1)&nbsp; &nbsp; go events.User.Trigger("new", "Ali")&nbsp; &nbsp; exitChannel := make(chan bool)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; events.Wg.Wait()&nbsp; &nbsp; &nbsp; &nbsp; close(exitChannel)&nbsp; &nbsp; }()&nbsp; &nbsp; canExit := false&nbsp; &nbsp; for !canExit {&nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; case x := <-events.Publish:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(x)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; case <- exitChannel:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; canExit = true&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}正如评论中所讨论的,需要初始化通道,缺少make,必须按以下方式完成:package eventsimport "sync"var (&nbsp; &nbsp; Wg&nbsp; &nbsp; &nbsp; sync.WaitGroup&nbsp; &nbsp; Publish chan string)func init() {&nbsp; &nbsp; Publish = make(chan string)}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go