V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
fumeboy
V2EX  ›  Go 编程语言

一个针对 golang reflect 对 func 反射过慢的优化技巧

  •  
  •   fumeboy · 2020-12-22 14:08:39 +08:00 · 1614 次点击
    这是一个创建于 1433 天前的主题,其中的信息可能已经有所发展或是发生改变。

    golang 的 func 的反射使用,目前还没有很合适的优化手段

    但是可以很巧妙地绕过对 func 的反射

    我个人语文水平难以表达出来,所以举一个实例进行说明

    低效例子

    gobench 测试大约 300 ns/op

    type banana struct {
    	value int
    	value2 int
    }
    
    func   apple(b *banana)int{
        return b.value
    }
    
    func parse_func(fn interface{}) func() int{
    	fnt := reflect.TypeOf(fn)
    	fnv := reflect.ValueOf(fn)
    
    	param := fnt.In(0).Elem()
    	return func() int {
    		arg := reflect.New(param)
    		resp := fnv.Call([]reflect.Value{arg}) // 严重耗时
    		return resp[0].Interface().(int)
    	}
    }
    
    fn := parse_func(apple)
    

    高效例子

    gobench 测试大约 50 ns/op

    type banana struct {
    	value int
    	value2 int
    }
    
    type iBanana interface {
    	apple() int
    }
    
    func (b *banana) apple() int {
    	return b.value
    }
    
    func parse_func(b iBanana) func() int{
    	t := reflect.TypeOf(b)
    	param := t.Elem()
    
    	return func() int {
    		arg := reflect.New(param).Interface().(iBanana)
    		return arg.apple() // 无需反射
    	}
    }
    
    fn := parse_func(&banana{})
    
    12 条回复    2020-12-26 16:51:49 +08:00
    wfhtqp
        1
    wfhtqp  
       2020-12-22 14:16:46 +08:00   ❤️ 1
    都实现接口了还需要反射?
    fumeboy
        2
    fumeboy  
    OP
       2020-12-22 14:19:41 +08:00
    @wfhtqp 哦, 这是函数和参数都需要反射的场景下使用的
    ArJun
        3
    ArJun  
       2020-12-22 14:26:28 +08:00   ❤️ 1
    楼主好像搞反了反射的实际意义··
    wfhtqp
        4
    wfhtqp  
       2020-12-22 14:28:26 +08:00   ❤️ 1
    如果不是特殊的项目请保持简单,避免过度设计。
    fumeboy
        5
    fumeboy  
    OP
       2020-12-22 14:32:33 +08:00
    @ArJun 可以指点得更明白一点吗
    fumeboy
        6
    fumeboy  
    OP
       2020-12-22 14:37:08 +08:00
    @ArJun 我现在使用反射的一般目的是实现伪泛型
    Mitt
        7
    Mitt  
       2020-12-22 22:56:21 +08:00 via iPhone   ❤️ 1
    你这传入了一个 interface 然后一套骚操作又把它转回那个 interface 了,那为啥不直接调用.apple() 反射的意义是啥
    eudore
        8
    eudore  
       2020-12-23 08:44:31 +08:00   ❤️ 1
    `arg := reflect.New(param).Interface().(iBanana)`迷之操作。 `return param.apple()` 不行?
    fumeboy
        9
    fumeboy  
    OP
       2020-12-23 12:21:50 +08:00
    @eudore
    @Mitt 参数是需要反射产生的. 原来的场景是 函数和参数都需要反射, 修改后, 只需要对参数反射
    Mitt
        10
    Mitt  
       2020-12-23 12:34:21 +08:00 via iPhone   ❤️ 1
    @fumeboy 那你应该是理解错了,如果你参数列表是动态的,那么你就不符合定义的接口了,也就无法传入了,你不能指定实体接口 而是用 interface{} 来反射
    fumeboy
        11
    fumeboy  
    OP
       2020-12-23 12:37:38 +08:00
    @Mitt 我要表达的就是 将参数写在 struct 里面, 然后用结构体方法的方式规避对 函数 的反射
    reus
        12
    reus  
       2020-12-26 16:51:49 +08:00 via Android
    你猜 (&banana{}).apple 是什么类型?
    你这个 parse_func 纯粹多余。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   926 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 19:49 · PVG 03:49 · LAX 11:49 · JFK 14:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.