Golang中如何实现模块间的双向通信?

Golang中如何实现模块间的双向通信? 在我们的项目中,有一个包含多个模块的系统,这些模块是特定的结构体,拥有大量可用的方法。这个项目创建于几年前,初衷是希望未来能轻松添加更多模块,并实现它们之间的便捷通信,因此其他开发者选择了NATS。但NATS的问题是,调用所需函数时需要编写过多的样板代码。有没有办法在两个模块对象之间建立双向通信,以便我可以从一个模块调用另一个模块,反之亦然。

例如:

func (*mod1) doSomething() {
    mod2.write()
}

func (*mod2) doSomethingToo() {
    mod1.read()
}

有没有办法在不使用WebSocket的情况下,在程序内部实现通信?或者这是不可行的吗?

感谢任何形式的帮助。


更多关于Golang中如何实现模块间的双向通信?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

所以你的问题是循环导入吗?有很多博客文章介绍了如何处理这个问题。

你考虑过以下方法吗:

  • RCP(例如通过Unix套接字)
  • 创建一个代理模块
  • 函数指针

更多关于Golang中如何实现模块间的双向通信?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Golang中实现模块间的双向通信,可以通过接口和依赖注入的方式来实现,避免使用外部消息系统如NATS带来的样板代码。以下是一个示例,展示如何通过接口定义和结构体嵌入实现模块间的直接调用:

// 定义模块接口
type ModuleA interface {
    DoSomething()
    SetModuleB(ModuleB)
}

type ModuleB interface {
    DoSomethingToo()
    SetModuleA(ModuleA)
}

// 实现模块A
type Mod1 struct {
    moduleB ModuleB
}

func (m *Mod1) DoSomething() {
    fmt.Println("Mod1 doing something")
    if m.moduleB != nil {
        m.moduleB.DoSomethingToo()
    }
}

func (m *Mod1) SetModuleB(b ModuleB) {
    m.moduleB = b
}

// 实现模块B
type Mod2 struct {
    moduleA ModuleA
}

func (m *Mod2) DoSomethingToo() {
    fmt.Println("Mod2 doing something too")
    if m.moduleA != nil {
        m.moduleA.DoSomething()
    }
}

func (m *Mod2) SetModuleA(a ModuleA) {
    m.moduleA = a
}

// 初始化并建立双向连接
func main() {
    mod1 := &Mod1{}
    mod2 := &Mod2{}
    
    mod1.SetModuleB(mod2)
    mod2.SetModuleA(mod1)
    
    mod1.DoSomething()
}

如果模块间需要异步通信,可以使用channel:

type Mod1 struct {
    mod2Chan chan string
    mod1Chan chan string
}

type Mod2 struct {
    mod1Chan chan string
    mod2Chan chan string
}

func (m *Mod1) DoSomething() {
    m.mod2Chan <- "request from mod1"
    response := <-m.mod1Chan
    fmt.Println("Mod1 received:", response)
}

func (m *Mod2) Start() {
    for {
        select {
        case msg := <-m.mod2Chan:
            fmt.Println("Mod2 received:", msg)
            m.mod1Chan <- "response from mod2"
        }
    }
}

func main() {
    mod1Chan := make(chan string)
    mod2Chan := make(chan string)
    
    mod1 := &Mod1{mod2Chan: mod2Chan, mod1Chan: mod1Chan}
    mod2 := &Mod2{mod1Chan: mod1Chan, mod2Chan: mod2Chan}
    
    go mod2.Start()
    mod1.DoSomething()
}

对于更复杂的场景,可以使用事件总线模式:

type Event struct {
    Type string
    Data interface{}
}

type EventBus struct {
    subscribers map[string][]chan Event
    mu          sync.RWMutex
}

func (eb *EventBus) Subscribe(eventType string, ch chan Event) {
    eb.mu.Lock()
    defer eb.mu.Unlock()
    eb.subscribers[eventType] = append(eb.subscribers[eventType], ch)
}

func (eb *EventBus) Publish(event Event) {
    eb.mu.RLock()
    defer eb.mu.RUnlock()
    
    if chans, ok := eb.subscribers[event.Type]; ok {
        for _, ch := range chans {
            ch <- event
        }
    }
}

type Mod1 struct {
    bus *EventBus
}

func (m *Mod1) DoSomething() {
    m.bus.Publish(Event{Type: "mod1_event", Data: "data from mod1"})
}

type Mod2 struct {
    bus *EventBus
}

func (m *Mod2) Start() {
    ch := make(chan Event)
    m.bus.Subscribe("mod1_event", ch)
    
    for event := range ch {
        fmt.Printf("Mod2 received event: %v\n", event)
    }
}

这些方法避免了外部依赖,直接在程序内部实现模块间的双向通信。接口方式适合同步调用,channel适合异步通信,事件总线适合多模块间的解耦通信。

回到顶部