Golang仿函数实现方法及效率测试
2016-10-30 22:35
190 查看
在C++ STL中,仿函数(functors)被大量用作改变算法的内在行为。
由于Golang不支持泛型,所以没法像C++那样灵活的使用仿函数。但是Golang有interface,函数是”一等公民”(可赋值给指定类型变量),因此,在Golang中实际上也可以像仿函数那样,通过具有相同参数和返回值的方法声明的不同对象,实现行为的差异化。
下面,详细讲述,Golang中的实现方法:
以下通过不同方法实现 Lesser(int,int)bool 和 Greater(int,int)bool的不同行为举例。
1. 通过interface实现
2.通过函数对象实现
3.通过转调对象实现
以下是3种方法的效率测试:
结论如下:
用interface实现多态,会占用两个指针(16字节空间) 执行效率上 大概慢一倍
使用函数指针 占用1个指针(8字节) 执行效率最高 但使用起来不够灵活
使用转调对象 只需要1个字节 执行效率跟函数指针差不多
推荐使用第三种方法(转调对象)的方法,使用数值枚举标识多路分发逻辑,效率上几乎没有损失,对外部引用对象的空间需求也比较小。
我将以上测试代码放在这里,欢迎查阅:
https://github.com/vipally/glab/blob/master/lab5/lab5_test.go
由于Golang不支持泛型,所以没法像C++那样灵活的使用仿函数。但是Golang有interface,函数是”一等公民”(可赋值给指定类型变量),因此,在Golang中实际上也可以像仿函数那样,通过具有相同参数和返回值的方法声明的不同对象,实现行为的差异化。
下面,详细讲述,Golang中的实现方法:
以下通过不同方法实现 Lesser(int,int)bool 和 Greater(int,int)bool的不同行为举例。
1. 通过interface实现
type Comparer interface { F(left, right int) bool } //create cmp object by name func CreateComparer(cmpName string) (r Comparer) { switch cmpName { case "": //default Lesser fallthrough case "Lesser": r = Lesser{} case "Greater": r = Greater{} default: //unsupport name panic(cmpName) } return } //Lesser type Lesser struct{} func (this Lesser) F(left, right int) (ok bool) { ok = left < right return } //Greater type Greater struct{} func (this Greater) F(left, right int) (ok bool) { ok = right < left return }
2.通过函数对象实现
type CmpFunc func(left, right int) bool //create cmp object by name func GetCmpFunc(cmpName string) (r CmpFunc) { switch cmpName { case "": //default Lesser fallthrough case "Lesser": r = Less case "Greater": r = Great default: //unsupport name panic(cmpName) } return } //Lesser func Less(left, right int) (ok bool) { ok = left < right return } //Greater func Great(left, right int) (ok bool) { ok = right < left return }
3.通过转调对象实现
type CmpObj byte const ( CMP_LESS CmpObj = iota CMP_GREAT ) func (me CmpObj) F(left, right int) (ok bool) { switch me { case CMP_LESS: ok = Less(left, right) case CMP_GREAT: ok = Great(left, right) default: panic(me) } return }
以下是3种方法的效率测试:
var ( cmp1 = CreateComparer("Lesser") cmp2 = GetCmpFunc("Lesser") cmp3 = CMP_LESS N = 100000000 ) func TestSize(t *testing.T) { fmt.Println("Interface", unsafe.Sizeof(cmp1)) fmt.Println("Func", unsafe.Sizeof(cmp2)) fmt.Println("Obj", unsafe.Sizeof(cmp3)) } func Benchmark_Interface(b *testing.B) { for i := 0; i < N; i++ { cmp1.F(1, 2) } } func Benchmark_Func(b *testing.B) { for i := 0; i < N; i++ { cmp2(1, 2) } } func Benchmark_Obj(b *testing.B) { for i := 0; i < N; i++ { cmp3.F(1, 2) } } //Interface 16 //Func 8 //Obj 1 //Benchmark_Interface-4 1000000000 0.55 ns/op //Benchmark_Func-4 2000000000 0.19 ns/op //Benchmark_Obj-4 2000000000 0.24 ns/op
结论如下:
用interface实现多态,会占用两个指针(16字节空间) 执行效率上 大概慢一倍
使用函数指针 占用1个指针(8字节) 执行效率最高 但使用起来不够灵活
使用转调对象 只需要1个字节 执行效率跟函数指针差不多
推荐使用第三种方法(转调对象)的方法,使用数值枚举标识多路分发逻辑,效率上几乎没有损失,对外部引用对象的空间需求也比较小。
我将以上测试代码放在这里,欢迎查阅:
https://github.com/vipally/glab/blob/master/lab5/lab5_test.go
相关文章推荐
- centos LB负载均衡集群 三种模式区别 LVS/NAT 配置 LVS/DR 配置 LVS/DR + keepalived配置 nginx ip_hash 实现长连接 LVS是四层LB 注意down掉网卡的方法 nginx效率没有LVS高 ipvsadm命令集 测试LVS方法 第三十三节课
- 绘制不规则位图方法总结,多种实现方法,全面测试比较
- 网络中树型菜单实现方法及其效率研究
- java动态代理类,测试,实现AOP,在执行target回调方法前后插入相关代码处理
- Linux下的dhcp测试实现方法
- MYSQL 随机 抽取实现方法及效率分析
- MYSQL 随机 抽取实现方法及效率分析
- 绘制不规则位图方法总结,多种实现方法,全面测试比较!
- python 测试实现方法
- 一种可用来测试算法效率的足够精确的计时方法【转】
- 网络中树型菜单实现方法及其效率研究
- 绘制不规则位图方法总结,多种实现方法,全面测试比较
- Tapestry4改进运行效率的实现方法
- 2种选择排序算法的效率比较(带测试main方法)
- 一种可用来测试算法效率的足够精确的计时方法
- Tapestry4改进运行效率的实现方法
- 用户体验测试的自动化实现 - 第二种检查Tab顺序的方法
- 基于cppunit的bcb中,运行某测试用例时,弹出窗口的实现方法
- java final方法执行效率测试
- 实现提高PHP效率的集中方法