Go1.18 类型约束的方法调用问题

WAZXY · · 1392 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

请教一下,下面两个基准测试的结果为什么会不一样,我看到生成的汇编也有很大不同,原因是什么 - 从基准测试的结果来看,第一个的性能更好一些,第二个的结果和接口调用方法的一样,更慢一点。 - 从我对泛型的认识来看,基准测试的结果至少也是相似。 1.不使用类型约束的情况 ~~~go type lesser[T ~int | ~string] struct { } func (l lesser[T]) Less(a, b T) bool { // 不同的类型可以有具体的实现 return a < b } // comp 改成具体的泛型类型 func testB[T ~int | ~string](b *testing.B, arr []T, comp lesser[T]) { b.ResetTimer() for i := 0; i < b.N; i++ { _ = comp.Less(arr[0], arr[99999]) } } // 这样的结果要比上面快的多 func BenchmarkTestB(b *testing.B) { // 模拟生成长度为10000000的随机数切片 arr := getTestArrSize(10000000) testB(b, arr, lesser[int]{}) } ~~~ 2.使用类型约束的情况 ~~~go type Comp[T any] interface { Less(i, j T) bool } type lesser2[T ~int | ~string] struct {} // 值类型和指针类型的接收器对结果没有实质性的影响 func (l *lesser2[T]) Less(a, b T) bool { return a < b } //Comp用作类型约束,comp为符合Comp[T]的类型的参数 func testD[T ~int | ~string, C Comp[T]](b *testing.B, arr []T, comp C) { // 打印的值和原类型的大小一样,从大小上来看comp不是接口 // comp 也没有发生逃逸 // 如果C类型是接口那为什么没有逃逸并且类型大小也和原来一样呢 // 从gcflag打印的结果来看也被内联了 // fmt.Println(unsafe.Sizeof(comp)) b.ResetTimer() for i := 0; i < b.N; i++ { _ = comp.Less(arr[0], arr[99999]) } } // 这种测试的结果和直接使用接口调用差不多 // 但是理论上应该和第二种情况一样才对 func BenchmarkTestD(b *testing.B) { arr := getTestArrSize(10000000) l := lesser2[int]{} testD(b, arr, &l) } ~~~ - 测试结果 ![结果.png](https://static.golangjob.cn/220414/8a529494fb97f464d49ee18e7f934372.png)

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1392 次点击  
加入收藏 微博
2 回复  |  直到 2022-04-15 12:42:20
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传