首页 文章详情

Go:字符串以及转换优化

Go语言精选 | 302 2021-06-18 00:47 0 0 0
UniSMS (合一短信)
点击上方蓝色“Go语言中文网”关注,每天一起学 Go

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

ℹ️  这篇文章基于 Go 1.14。

在 Go 语言中,将 byte 数组转换为 string 时,随着转换后字符串的拷贝,可能会触发内存分配。然而,将 bytes 转换为 string 仅仅是为了满足代码约束,比如在 switch 语句中的比较,又比如在 map 中的 key,这些场景下的转换绝对是在浪费 CPU 时间。来一起看一些案例,以及一些已有的优化。

本文是 Go语言中文网组织的 GCTT 翻译,发布在 Go语言中文网公众号,转载请联系我们授权。

转换操作(Conversion)

将 byte 数组转换为 string 涉及的操作有:

  • 如果变量超过了当前堆栈帧的作用域,在堆上为新的 string 分配内存。
  • bytes 到 string 的拷贝

关于逃逸分析的更多细节,建议阅读我的文章:“Go:介绍逃逸分析。[1]

这是完成这两个步骤的简要程序:

这是该转换操作的示意图:

如果想更多了解 copy 函数,建议阅读我的文章“Go:切片以及内存管理[2]

在运行时层面,Go 在转换期间只提供一种优化。如果转换的 byte 数字实际只包含一个字节,返回的 string 会指向一个静态的 byte 数组,该数组嵌入在运行时中:

然而,如果这个 string 之后被修改,分配新值之前会从堆上面分配内存。

Go 编译器同样提供一些优化,可以省略我们所见到的两个转换阶段。

Switch

先以一个以比较为目的,转换为 string 的示例开始:

这个用来说明字符串优化的实例通过使用 getBytes 函数强制在堆上进行分配。这样避免了要介绍的字符串优化被编译器的其他优化所隐藏。

在这个示例中,仅有 switch 指令使用了转换,而且由于仅仅需要与实际内容进行比较,Go 可以避免转换操作。Go 实际上通过移除转换操作,并且直接指向底层的 byte 数组来优化这段代码。

我们也可以通过生成的汇编指令来了解具体优化细节:

Go 在比较操作中直接使用返回的 bytes。首先比较 byte 数组和 case 语句(case 后面的字符串)的大小,之后检查字符串本身(字面值)。在 switch 语句外分配 string,会导致内存的分配,因为编译器无法得知这个 string 后续是否还会使用。

优化

switch 并不是字符串转换的唯一的一个优化。Go 编译器会在其他示例中应用这样的优化,比如:

  • 访问 map 中的元素。这是一个例子:

当访问 map 时,实际上不需要进行转换,这样能使访问更快。

  • 字符串连接。这是一个例子:

byte 数组与一些 string 的连接不会引起任何内存分配,也不会引起 byte 的任何转换。就像前面看到的一样,连接会直接引用底层的数组。

  • 字符串比较。这里是一些例子:

这个例子与 switch 类似。首先比较 string 的大小和 byte 数组的大小,之后再比较字符串。


via: https://medium.com/a-journey-with-go/go-string-conversion-optimization-767b019b75ef

作者:Vincent Blanchon[3]译者:dust347[4]校对:polaris1119[5]

本文由 GCTT[6] 原创编译,Go 中文网[7] 荣誉推出,发布在 Go语言中文网公众号,转载请联系我们授权。

参考资料

[1]

Go:介绍逃逸分析。: https://studygolang.com/articles/34524

[2]

Go:切片以及内存管理: https://medium.com/a-journey-with-go/go-slice-and-memory-management-670498bb52be

[3]

Vincent Blanchon: https://medium.com/@blanchon.vincent

[4]

dust347: https://github.com/dust347

[5]

polaris1119: https://github.com/polaris1119

[6]

GCTT: https://github.com/studygolang/GCTT

[7]

Go 中文网: https://studygolang.com/



推荐阅读


福利

我为大家整理了一份从入门到进阶的Go学习资料礼包,包含学习建议:入门看什么,进阶看什么。关注公众号 「polarisxu」,回复 ebook 获取;还可以回复「进群」,和数万 Gopher 交流学习。

good-icon 0
favorite-icon 0
收藏
回复数量: 0
    暂无评论~~
    Ctrl+Enter