我有以下代码:
//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)
}
}
}我得到的输出如下所示,即没有通过通道进行交换。

如果我将for { select {} }循环替换为for x := range <-events.Publish { }循环,则得到以下错误:
PS D:\Deployment\event-driven> go run edriven
Starting
[Ali]
[Hasan]
[[Hasan Ali]] 0
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive (nil chan)]:
main.main()
D:/Deployment/event-driven/main.go:17 +0x1c5
goroutine 6 [chan send (nil chan)]:
edriven/events.init.0.func1({0xc000086010?, 0x1?, 0x1?})
D:/Deployment/event-driven/events/user.go:12 +0x6c
edriven/events.(*Events).Trigger(0x0?, {0xe45ca0, 0x3}, {0xc000086000, 0x1, 0x1})
D:/Deployment/event-driven/events/setup.go:34 +0x129
created by main.main
D:/Deployment/event-driven/main.go:11 +0xb5
goroutine 7 [chan send (nil chan)]:
edriven/events.init.0.func2({0xc000180010?, 0x1?, 0x1?})
D:/Deployment/event-driven/events/user.go:23 +0x45
edriven/events.(*Events).Trigger(0x0?, {0xe45db9, 0x4}, {0xc000180000, 0x1, 0x1})
D:/Deployment/event-driven/events/setup.go:34 +0x129
created by main.main
D:/Deployment/event-driven/main.go:13 +0x15d
goroutine 8 [chan send (nil chan)]:
edriven/events.init.0.func1({0xc000050260?, 0x1?, 0x1?})
D:/Deployment/event-driven/events/user.go:12 +0x6c
edriven/events.(*Events).Trigger(0x0?, {0xe45ca0, 0x3}, {0xc000050250, 0x1, 0x1})
D:/Deployment/event-driven/events/setup.go:34 +0x129
created by main.main
D:/Deployment/event-driven/main.go:15 +0x1aa
exit status 2
PS D:\Deployment\event-driven> 发布于 2022-07-10 20:37:48
这段代码是有问题的
for {
select {
case x := <- events.Publish:
fmt.Println(x)
default:
fmt.Println("waiting for data ...")
time.Sleep((time.Duration(math.MaxInt64)))
}
}当调用select并假设Publish通道仍然为空时,默认情况将运行,并使用time.Sleep语句永久阻塞主循环。因此,即使Publish通道接收到来自另一个go例程的数据,主要的go例程仍然被困在睡眠语句上。
当您想要将时间等待与通道事件组合起来时,您可以这样做:
timerChannel := time.NewTimer(duration)
select {
case <-timerChannel.C:
{
// time out
}
case x := <-events.Publish:
{
fmt.println(x)
}
}但是,由于您的意图似乎只是阻止main退出,那么它就更简单了:
for {
x := <- events.Publish: // blocks until Publish channel has data
fmt.Println(x)
}但是正如你所呼吁的那样,这会导致一个僵局,因为在你退出后的三个例程之后,就没有什么可做的了。
快速修复:
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")
exitChannel := make(chan bool)
go func() {
events.Wg.Wait()
close(exitChannel)
}()
canExit := false
for !canExit {
select {
case x := <-events.Publish:
{
fmt.Println(x)
}
case <- exitChannel:
{
canExit = true
}
}
}
}正如注释中所讨论的,需要初始化通道,缺少一个制作,它必须执行如下操作:
package events
import "sync"
var (
Wg sync.WaitGroup
Publish chan string
)
func init() {
Publish = make(chan string)
}https://stackoverflow.com/questions/72931632
复制相似问题