Go 语言没有内置的事件机制(如 C# 的 event、JavaScript 的 EventEmitter),但 完全可以通过标准库和惯用模式实现强大、类型安全、高性能的事件模型。是否“完整”取决于你的需求 —— 对于绝大多数场景,Go 的并发原语(channel + goroutine)足以构建比传统回调式事件系统更清晰、更可控的事件驱动架构。
event
EventEmitter
💡 Go 的哲学:用组合和并发原语解决问题,而非引入新概念。
适用于:1 对多通知、流式事件
type EventBus struct { subscribers []chan Event mu sync.RWMutex } func (eb *EventBus) Subscribe() <-chan Event { ch := make(chan Event, 1) eb.mu.Lock() eb.subscribers = append(eb.subscribers, ch) eb.mu.Unlock() return ch } func (eb *EventBus) Publish(event Event) { eb.mu.RLock() defer eb.mu.RUnlock() for _, ch := range eb.subscribers { // 非阻塞发送(防慢消费者阻塞) select { case ch <- event: default: // 可选:记录丢弃或关闭慢 consumer } } }
✅ 优点:
Event
适用于:单次监听、同步处理
type EventHandler func(event Event) type EventEmitter struct { handlers []EventHandler } func (e *EventEmitter) On(h EventHandler) { e.handlers = append(e.handlers, h) } func (e *EventEmitter) Emit(event Event) { for _, h := range e.handlers { h(event) // 同步调用 } }
⚠️ 缺点:
🛠 改进:在 goroutine 中异步执行: go func(h EventHandler, ev Event) { h(ev) }(h, event)
🛠 改进:在 goroutine 中异步执行:
go func(h EventHandler, ev Event) { h(ev) }(h, event)
适用于:需要多态、解耦组件
type Observer interface { OnEvent(event Event) } type Subject struct { observers []Observer } func (s *Subject) AddObserver(o Observer) { s.observers = append(s.observers, o) } func (s *Subject) Notify(event Event) { for _, o := range s.observers { o.OnEvent(event) } }
✅ 适合:大型系统中模块间松耦合通信。
asaskevich/EventBus
如果你想要类似 JS 的 API:
import "github.com/asaskevich/EventBus" bus := EventBus.New() bus.Subscribe("user.login", func(user string) { fmt.Println("User logged in:", user) }) bus.Publish("user.login", "alice")
⚠️ 但注意:
interface{}
🚫 官方建议:优先使用标准库原语。
🎯 Go 的 channel 本质是一个“带队列的事件总线”,且更可控。
// 定义事件类型 type SessionEvent struct { Type string // "text", "audio", "close" Data interface{} } type Session struct { events chan SessionEvent ctx context.Context } func NewSession() *Session { ctx, cancel := context.WithCancel(context.Background()) return &Session{ events: make(chan SessionEvent, 10), ctx: ctx, } } // 发布事件 func (s *Session) emitText(text string) { select { case s.events <- SessionEvent{"text", text}: case <-s.ctx.Done(): } } // 监听事件(Client 使用) func (c *Client) listenSessionEvents() { for { select { case ev := <-c.session.events: switch ev.Type { case "text": c.sendText(ev.Data.(string)) case "close": return } case <-c.session.ctx.Done(): return } } }
✅ 这就是一个完整的、类型安全、可取消、带背压的事件系统!
Go 没有内置事件机制,但它的并发原语(channel + goroutine + select)构成了一个更强大、更安全、更符合工程实践的“事件驱动”基础。
context
💡 记住:在 Go 中,channel 就是你的事件总线。
所以,Go 的事件模型不仅“完整”,而且更优雅、更高效 —— 只要你用对了方式。
Github开源生信云平台 DEMO