dobyte / due

A lightweight distributed game server framework developed based on Go language.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

hexxv opened this issue · comments

commented

我目前使用的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)
}
commented

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