英文:
Channel is not recieving data or giving dead block
问题
我已经翻译好了你提供的代码部分,如下所示:
//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", []interface{}{"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 ...interface{}) {
fmt.Println(payload[0])
//message := make(map[string]string)
//message["new"] = "done new"
Publish <- "{'new':'done'}"
Wg.Done()
})
User.register("name", func(payload ...interface{}) {
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(...interface{}) // <-chan string // func(...any) ([]any, error)
}
type Events struct {
handlers []Event
}
func (e *Events) register(name string, action func(...interface{})) {
e.handlers = append(e.handlers, Event{
Name: name,
Action: action,
})
}
func (e *Events) Trigger(name string, payload ...interface{}) {
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>
希望这些翻译对你有帮助!如果你有任何其他问题,请随时提问。
英文:
I've the below code:
//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)))
}
}
}
And
//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()
})
}
And
//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)
}
}
}
The output I got is as below, that is nothing is exchanged through the channels
If I replaced the for { select {} }
loop by the for x := range <-events.Publish { }
loop then I get the below error:
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>
答案1
得分: 2
这段代码有问题:
for {
select {
case x := <-events.Publish:
fmt.Println(x)
default:
fmt.Println("waiting for data ...")
time.Sleep((time.Duration(math.MaxInt64)))
}
}
当select
被调用并且假设Publish
通道仍然为空时,default语句将运行并使用time.Sleep
语句永远阻塞主循环。因此,即使Publish
通道从另一个go例程接收到数据,主go例程仍然被卡在Sleep语句上。
每当你想要将定时等待与通道事件结合时,可以这样做:
timerChannel := time.NewTimer(duration)
select {
case <-timerChannel.C:
{
// 超时
}
case x := <-events.Publish:
{
fmt.Println(x)
}
}
但是,由于你的意图似乎只是阻止main
退出,那么更简单的方法是:
for {
x := <-events.Publish // 阻塞直到Publish通道有数据
fmt.Println(x)
}
但正如你指出的,这会导致死锁,因为在你的三个go例程退出后,没有其他任务可执行。
快速修复:
func main() {
fmt.Println("Starting")
events.Wg.Add(1)
go events.User.Trigger("new", "Hasan")
events.Wg.Add(1)
go events.User.Trigger("name", []interface{}{"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
}
}
}
}
如评论中所讨论的,需要初始化通道,缺少了一个make
,应该这样做:
package events
import "sync"
var (
Wg sync.WaitGroup
Publish chan string
)
func init() {
Publish = make(chan string)
}
英文:
This block of code is problematic
for {
select {
case x := <- events.Publish:
fmt.Println(x)
default:
fmt.Println("waiting for data ...")
time.Sleep((time.Duration(math.MaxInt64)))
}
}
When select
is invoked and assuming the Publish
channel is still empty, the default case will run and block the main loop forever with the time.Sleep
statement. Hence, even if the Publish
channel receives data from another go-routine, the main go-routine is still stuck on that Sleep statement.
Any time you want to combine a timed wait with a channel event, you can do this:
timerChannel := time.NewTimer(duration)
select {
case <-timerChannel.C:
{
// time out
}
case x := <-events.Publish:
{
fmt.println(x)
}
}
But since your intent appears to just block main
from exiting, then it's even simpler:
for {
x := <- events.Publish: // blocks until Publish channel has data
fmt.Println(x)
}
But as you called out, that leads to a deadlock because after your three go-routines after exited, there's nothing left to do.
Quick fix:
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
}
}
}
}
As discussed in the comments, channel is required to be initialized, a make is missing, it has to be done as:
package events
import "sync"
var (
Wg sync.WaitGroup
Publish chan string
)
func init() {
Publish = make(chan string)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论