这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天
Go 编译器优化
编译器优化带来的好处:
- 用户无感知,重新编译就可以获得性能收益
- 通用性优化
而编译器现状是:
- 采用的优化少
- 编译时间短,没有进行较复杂的代码分析和优化
编译优化的思路
- 常见:面向后端长期执行任务
- Tradeoff:用编译时间换取更高效的机器码
Beast Mode(字节自研)
- 函数内联
- 逃逸分析
- 默认栈大小调整
- 边界检查消除
- 循环展开
- ......
函数内联
内联指的就是将被调用函数的函数体(callee)的副本替换到调用位置(caller)上,同时重写代码以反映参数的绑定。
内联的优点如下:
- 消除函数调用开销,例如传递参数、保存寄存器等
- 将过程间分析转换为过程内分析,帮助其他优化,例如逃逸分析
有优点必然也有缺点,其缺点如下:
- 函数体变大,对于instruction cache不友好
- 编译生成的Go镜像变大
不过在大多数情况下,内联都是正向优化
在Golang函数中内联受到的限制比较多
- 语言特性,例如interface、defer等,限制了函数的内联
- 内联的策略非常保守
可以使用 micro-benchmark 快速验证和对比性能优化结果。
逃逸分析
逃逸分析指的是分析代码中指针的动态作用域,以确定指针在何处可以被访问。
其大致思路如下:
- 从对象分配处出发,沿着控制流,观察对象的数据流
- 若发现指针p在当前作用域s下有以下行为:
- 作为参数传递给其他参数
- 传递给全局变量
- 传递给其他的goroutine
- 传递给已逃逸的指针指向的对象
- 那么就说指针p指向的对象逃逸出了s,反之则没有逃逸出s
Beast Mode
其为字节自研的编译优化方法。
主要介绍了函数内联+逃逸分析。
函数内联
对于函数内联,其调整了函数内联的策略,从而使得更多函数被内联。
其好处就是:
- 降低函数调用的开销
- 增加了其他优化的机会:逃逸分析
不过有些许的开销
- Go镜像增加了10%左右
- 编译时间增加
逃逸分析
对于逃逸分析,由于函数内联拓展了函数边界,因此更多的对象都不会逃逸出来。
其所做的优化是将未逃逸的对象在栈上分配,因为对象在栈上分配和回收很快,只需要移动sp指针即可。而减少heap上的内存分配,可以降低GC的负担。
Go 的框架三件套
GKH 框架三件套
- Gorm
Gorm 是一个已经迭代了10年+的功能强大的ORM框架,在字节内部被广泛使用并且拥有非常丰富的开源扩展。
- Kitex
Kietx 是字节内部的 Golang 微服务 RPC 框架,具有高性能,强可扩展的主要特点,支持多协议并且拥有丰富的开源扩展。
- Hertz
Hertz 是字节内部的 HTTP 框架,参考了其他开源框架的优势,结合字节跳动内部的需求,具有高易用性、高性能、高扩展特点。