dobyte / due

A lightweight distributed game server framework developed based on Go language.
MIT License
403 stars 60 forks source link

获取事件处理函数指针地址问题 #22

Open hexxv opened 1 month ago

hexxv commented 1 month ago

我目前使用的V1版本,代码如下:

// eventbus\nats\consumer.go
func (c *consumer) addHandler(handler eventbus.EventHandler) int {

    pointer := reflect.ValueOf(handler).Pointer()

    c.rw.Lock()
    defer c.rw.Unlock()

    c.handlers[pointer] = handler

    return len(c.handlers)
}

经调试发现:

// eventbus\nats\consumer.go

pointer := reflect.ValueOf(handler).Pointer() // pointer总是返回同一个值

问题:

pointer总是返回同一个值 这将导致:同一个 topic,注册两个处理函数,后注册的会顶掉先注册的。

于是,我在V2发现了这个变动, 代码如下:

// 添加处理器
func (c *consumer) addHandler(handler eventbus.EventHandler) int {
    pointer := reflect.ValueOf(handler).Pointer()

    c.rw.Lock()
    defer c.rw.Unlock()

    if _, ok := c.handlers[pointer]; !ok {
        c.handlers[pointer] = make([]eventbus.EventHandler, 0, 1)
    }

    c.handlers[pointer] = append(c.handlers[pointer], handler)

    return len(c.handlers[pointer])
}

疑问点:

  1. 取pointer的目的? 看上去,V1版本是保证同一个处理函数无论注册多少次只调用一次, V2版本变更为 同一个处理函数注册n次调用n次。
  2. 个人愚见:v2版本看上去像是作者发现v1版本的问题后采用了变更设计的解决方案(我今天使用v1版本刚好遇到了这个问题),如果仅仅是解决V1版本的问题,好像修改一下就可以了:

    // eventbus\nats\consumer.go
    func (c *consumer) addHandler(handler eventbus.EventHandler) int {
    
    // pointer := reflect.ValueOf(handler).Pointer()
        pointer := reflect.ValueOf(unsafe.Pointer(&handler)).Pointer()
    
    c.rw.Lock()
    defer c.rw.Unlock()
    
    c.handlers[pointer] = handler
    
    return len(c.handlers)
    }
dobyte commented 1 month ago

感谢你提出的问题和解决方案。v2版本的初衷确实是为了一个事件同时被多个订阅函数进行处理。当时还考虑到取消订阅的API,因而采用了slice的的方案来存入多个函数。但目前的取消订阅的API会出现一个取消全部都取消的问题,因此后续会对该API进行优化,到时候会采用你的方案来进行处理。