4

Go: 内置函数优化

 3 years ago
source link: https://studygolang.com/articles/35199
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

由 Renee French 创作的原始 Go Gopher 作品,为“ Go 的旅程”创作的插图。

ℹ️ 这篇文章基于 Go 1.13。

Go 语言提供内置函数来辅助开发者处理 channel,slice,或者 map。一些内置函数有着像样的内部实现,比如 make(),而有的内置函数完全没有实现,而是由编译器所管理。让我们一起分析一些内置函数,来理解 Go 如何处理它们。

Slices

如果可以事先知道的话,Go 有时可以把一个在运行时完成的函数调用替换为它的结果。来看一个使用切片的例子:

func main() {
   s := make([]int, 0, 6)
   s = append(s, 12)
   s = append(s, 34)

   l := len(s)
   println("the length is ", l)

   c := cap(s)
   println("the capacity is ", c)
}

函数 lencap 实际上没有具体实现。编译器能够跟踪在切片上所做的更改,并将长度或者容量函数替换为可以代表它们的常量。这是汇编代码表示:

replace-length-or-capacity%20function-constant.png

但是,编译器不可能永远确定切片的大小。在这种情况下,比如,切片是一个函数的参数,这个函数没有指定其大小。这是一个例子:

func main() {
   s := make([]int, 0, 6)
   s = append(s, 12, 34)
   getLength(s)
}

//go:noinline
func getLength(s []int) {
   l := len(s)
   println("the length is", l)
}

这是生成的指令:

1_9eu8BEzj2ATNR2tmdsCMfg.png

由于 Go 无法了解 getLength() 方法被如何使用,只能直接从内存里面读取切片的长度。同样的行为也会引用在切片的容量上。

Go 通常会指向切片的长度,防止不良的内存访问,比如越界读取。更多信息,建议阅读我的文章“Go:边界检查保证内存安全”。

Unsafe

unsafe 包同样暴露了没有任何实现的函数。由 Go 标准库提供的定义原型,仅仅用作说明文档:

Example of the documentation of the unsafe package

这是这个包的例子:

type T1 struct {
   a int64
   b bool
}

func main() {
   t1 := T1{}

   println("size of the struct:", unsafe.Sizeof(t1))
   println("alignment of the struct:", unsafe.Alignof(t1))
}
Output:
size of the struct: 16
alignment of the struct: 8

再次,编译器有着关于结构的足够信息,可以直接将值写为常量:

write-the-values-as-constants-directly.png

Go 语言提供了更多的内置函数,比如 makecopy。关于 copy 函数的更多细节信息,建议阅读我的文章“Go:切片以及内存管理”,该文章详细阐述了优化细节。关于在 map 上的优化,建议阅读“Go:根据代码设计 map——第二部分” 来深入了解。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK