Golang中channel无法接收数据或出现死锁问题如何解决
Golang中channel无法接收数据或出现死锁问题如何解决 我有以下代码:
//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
/*var Publish chan map[string]string
func init() {
Publish = make(chan map[string]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>
更多关于Golang中channel无法接收数据或出现死锁问题如何解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang中channel无法接收数据或出现死锁问题如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
问题在于 events.Publish 通道未初始化。在 events/setup.go 中,Publish 被声明为 chan string,但未使用 make 创建,导致通道为 nil。向 nil 通道发送或接收数据都会导致死锁。
以下是修复后的代码:
// events/setup.go
package events
import "sync"
var Wg sync.WaitGroup
var Publish chan string
func init() {
Publish = make(chan string) // 初始化通道
}
type Event struct {
Name string
Action func(...any)
}
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)
}
}
}
同时,main.go 中的无限循环需要调整,以避免阻塞并正确等待所有 goroutine 完成:
// main.go
package main
import (
"edriven/events"
"fmt"
"sync"
)
func main() {
fmt.Println("Starting")
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
events.User.Trigger("new", "Hasan")
}()
wg.Add(1)
go func() {
defer wg.Done()
events.User.Trigger("name", []any{"Hasan", "Ali"})
}()
wg.Add(1)
go func() {
defer wg.Done()
events.User.Trigger("new", "Ali")
}()
// 启动一个 goroutine 来接收通道数据
go func() {
for x := range events.Publish {
fmt.Println("Received:", x)
}
}()
wg.Wait()
close(events.Publish) // 关闭通道,结束接收循环
}
如果希望保持原有的 WaitGroup 设计,可以修改 events/user.go 中的 init 函数,确保 User 被正确初始化:
// events/user.go
package events
import "fmt"
var User Events
func init() {
User = Events{} // 初始化 User
User.register("new", func(payload ...any) {
fmt.Println(payload[0])
Publish <- "{'new':'done'}"
Wg.Done()
})
User.register("name", func(payload ...any) {
for index, person := range payload {
fmt.Println(person, index)
}
Publish <- "{'name':'done'}"
Wg.Done()
})
}
主要修改点:
- 在
events/setup.go的init函数中初始化Publish通道。 - 在
events/user.go的init函数中初始化User变量。 - 在
main.go中使用sync.WaitGroup等待所有触发操作完成,然后关闭通道。

