Golang Go语言中 interface.Method 性能为何会比 switch type 差?
Golang Go语言中 interface.Method 性能为何会比 switch type 差?
测试代码:
package main
import (
"testing"
)
type InterfaceA interface {
Name() string
}
type InterfaceB interface {
Name() string
Add()
}
type A struct {
v int
}
func (*A) Name() string {
return "A"
}
func (a *A) Add() {
a.v += 1
}
type B struct {
A
}
func (*B) Name() string {
return "B"
}
func BenchmarkNormal(b *testing.B) {
switchFunc := func(v *A) {
v.Add()
}
for i := 0; i < b.N; i++ {
v := new(A)
switchFunc(v)
}
}
func BenchmarkInterface(b *testing.B) {
switchFunc := func(v interface{}) {
switch n := v.(type) {
case *A:
n.Add()
case *B:
n.Add()
}
}
for i := 0; i < b.N; i++ {
v := new(A)
switchFunc(v)
}
}
func BenchmarkInterface1(b *testing.B) {
switchFunc := func(v InterfaceA) {
switch v.Name() {
case "A":
v.(*A).Add()
case "B":
v.(*B).Add()
}
}
for i := 0; i < b.N; i++ {
v := new(A)
switchFunc(v)
}
}
func BenchmarkInterface2(b *testing.B) {
switchFunc := func(v interface{}) {
v.(InterfaceB).Add()
}
for i := 0; i < b.N; i++ {
v := new(A)
switchFunc(v)
}
}
func BenchmarkInterface3(b *testing.B) {
switchFunc := func(v InterfaceB) {
v.Add()
}
for i := 0; i < b.N; i++ {
v := new(A)
switchFunc(v)
}
}
func BenchmarkInterface4(b *testing.B) {
switchFunc := func(v InterfaceB) {
v.Name()
}
for i := 0; i < b.N; i++ {
v := new(A)
switchFunc(v)
}
}
func BenchmarkInterface5(b *testing.B) {
switchFunc := func(v InterfaceB) {
v.Name()
v.Add()
}
for i := 0; i < b.N; i++ {
v := new(A)
switchFunc(v)
}
}
测试结果:
└──╼ go test -test.bench=".*" . -benchmem
goos: darwin
goarch: amd64
pkg: org
cpu: Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz
BenchmarkNormal-8 1000000000 0.2542 ns/op 0 B/op 0 allocs/op
BenchmarkInterface-8 1000000000 0.8415 ns/op 0 B/op 0 allocs/op
BenchmarkInterface1-8 72095432 15.48 ns/op 8 B/op 1 allocs/op
BenchmarkInterface2-8 55137806 21.07 ns/op 8 B/op 1 allocs/op
BenchmarkInterface3-8 799164643 1.449 ns/op 0 B/op 0 allocs/op
BenchmarkInterface4-8 767046265 1.519 ns/op 0 B/op 0 allocs/op
BenchmarkInterface5-8 72075118 15.82 ns/op 8 B/op 1 allocs/op
PASS
ok org 7.915s
还有就是 interface 接口单独测试 Name()或者 Add()性能都差不多,可一旦两个一起调用,性能几乎减少了 10 倍,有大佬研究过这个问题吗?
更多关于Golang Go语言中 interface.Method 性能为何会比 switch type 差?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
内存逃逸?
更多关于Golang Go语言中 interface.Method 性能为何会比 switch type 差?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
能享受到 cpu 的分支预测吧
另外可以反汇编看看编译器有没有做什么优化。
所有 1 allocs/op 的 bench 都是逃逸(编译器判断 new 的变量有外部引用)。
不过没搞清楚你要比较的到底是哪两个。🤣
是内联优化,BenchmarkInterface 、BenchmarkInterface3 、BenchmarkInterface3 这三个都在内联优化完全被展开了,并没有两次函数调用的行为,所以性能很高,你这个测试是在 1.16 后面跑的吧,1.16 以前内联优化并没有去掉运行时类型检查,所以性能并没那么高
非常感谢,我再研究一下
在Golang(Go语言)中,interface.Method
的性能通常会比 switch type
差,这主要归因于接口的动态分派特性和Go语言的运行时机制。
-
动态分派:接口在Go中是一种抽象类型,它允许定义对象的行为而不需要了解对象的具体类型。当一个接口变量调用其方法时,Go运行时需要在运行时确定具体实现该方法的具体类型,这称为动态分派。这个过程涉及到额外的查找和跳转,从而增加了执行开销。
-
类型断言和类型转换:在使用
interface.Method
时,如果需要在接口类型和具体类型之间进行转换,会涉及到类型断言(type assertion
)或类型转换(type conversion
),这些操作同样需要运行时支持,并且可能引入性能损耗。 -
switch type优化:相比之下,
switch type
语句是编译时确定的,Go编译器可以对它进行优化,比如生成类型特定的代码路径,从而避免了运行时的类型查找和跳转。这种编译时优化使得switch type
在执行时能够更高效地确定要执行的代码路径。 -
缓存和内联:编译器还可以对
switch type
进行内联优化,将相关代码直接嵌入到调用点,减少函数调用的开销。此外,现代处理器对分支预测的优化也能显著提高switch type
的性能。
综上所述,由于接口的动态分派特性和运行时开销,interface.Method
的性能通常会比 switch type
差。然而,在需要高度抽象和灵活性的场景中,接口仍然是Go语言中不可或缺的工具。