返回介绍

上卷 程序设计

中卷 标准库

下卷 运行时

源码剖析

附录

8.2 性能

发布于 2024-10-12 19:15:48 字数 2510 浏览 0 评论 0 收藏 0

“泛型实现有性能问题!”,争论源于 “所有类型的指针都属于同一 GCshape,共享同一份代码实例”。

编译器会插入一条指令,以字典装载类型信息,通过寄存器传递给目标代码。
必要时以接口方式处理,可能引发 动态调用无法内联内存逃逸 等性能问题。

编译器会尝试优化掉中间环节。比如内联,直接调用目标方法。

type A int32
type B int64

func (a A) test() { println(a) }
func (b B) test() { println(b) }
type Tester interface {
	A | B
	test()
}

func test[T Tester](a T) {
	a.test()
}

func main() {
	var a A = 1
	var b B = 2

	test(a)
	test(b)
}
$ go build -gcflags "-l"
$ go tool objdump -S -s "main\.main" ./test

TEXT main.main(SB)
func main() {

	test(a)
  0x45772e		LEAQ main..dict.test[main.A](SB), AX	
  0x457735		MOVL $0x1, BX				
  0x45773a		CALL main.test[go.shape.int32](SB)	   // 泛型函数调用
  
	test(b)
  0x45773f		LEAQ main..dict.test[main.B](SB), AX	
  0x457746		MOVL $0x2, BX				
  0x45774b		CALL main.test[go.shape.int64](SB)	
  
}
$ go build
$ go tool objdump -S -s "main\.main" ./test

TEXT main.main(SB)
func main() {

	test(a)
  0x45772e		NOPL	; 内联,直接方法调用。
  
	a.test()
  0x45772f		MOVL $0x1, AX				
  0x457734		LEAQ main..dict.test[main.A](SB), DX	
  0x45773b		LEAQ 0xffffff1e(IP), CX			# 0x457660 <main.A.test>
  0x457742		CALL CX					
  
	test(b)
  0x457744		NOPL		
  
	a.test()
  0x457745		MOVL $0x2, AX				
  0x45774a		LEAQ main..dict.test[main.B](SB), DX	
  0x457751		LEAQ 0xffffff68(IP), CX		 # 0x4576c0 <main.B.test>
  0x457758		CALL CX				
  
}

与之相比,指针版本存在内存逃逸。

type Tester interface {
	*A | *B
	test()
}

func test[T Tester](a T) {
	a.test()
}

// -----------------------------

func main() {
	var a A = 1
	var b B = 2

	test(&a)
	test(&b)
}
$ go build
$ go tool objdump -S -s "main\.main" ./test

TEXT main.main(SB)
func main() {

	var a A = 1
  0x45766e		LEAQ 0x64ab(IP), AX		
  0x457675		CALL runtime.newobject(SB)	
  0x45767a		MOVQ AX, 0x18(SP)		
  0x45767f		MOVL $0x1, 0(AX)		
  
	var b B = 2
  0x457685		LEAQ 0x64f4(IP), AX		
  0x45768c		CALL runtime.newobject(SB)	
  0x457691		MOVQ AX, 0x10(SP)		
  0x457696		MOVQ $0x2, 0(AX)		
  
	test(&a)
  0x45769d		NOPL			
  
	a.test()
  0x45769e		LEAQ main..dict.test[*main.A](SB), DX	
  0x4576a5		MOVQ 0x18(SP), AX			
  0x4576aa		LEAQ main.(*A).test(SB), BX		
  0x4576b1		CALL BX					
  
	test(&b)
  0x4576b3		NOPL			
  
	a.test()
  0x4576b4		MOVQ 0x10(SP), AX			
  0x4576b9		LEAQ main..dict.test[*main.B](SB), DX	
  0x4576c0		LEAQ main.(*B).test(SB), CX		
  0x4576c7		CALL CX		
  
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文