case when 包含某个字符_Go: 字符串和转换优化

ℹ️ 本文基于Go1.14。

在Go中,将字节数组转换为字符串可能会涉及到内存分配以及转换后的字符串的副本。但是,仅将字节转换为字符串以满足代码约束(例如switch语句中的比较或作为map的key)绝对是浪费CPU时间。让我们回顾一些案例并进行优化。

转换

从字节数组转换为字符串涉及:

  • 如果变量超过当前栈帧,则在堆上分配新字符串。

  • 转换后的字符串的副本。

这是完成这两个步骤的示例程序:

b9dd1be2635942fadbb65aaa3e8edfd5.png

这是转换的图示:

002bf07eb15737bda13b894796e25d66.png

在运行时,Go在转换期间仅提供一种优化。如果被转换的字节数组实际上只包含一个字节,则返回的字符串将指向运行时嵌入的静态字节数组:

730b4bc59a5b5f3c341817da9ea91590.png

但是,如果以后修改此字符串,它将在分配新值之前从堆中分配内存。

Go编译器还提供了一些优化功能,可以跳过我们看到的转换的两个阶段。

Switch

让我们看一个用于比较意图的转换示例:

b575f82f409d998992f567ecc8e3a929.png

这个例子用于说明字符串优化,将会通过getBytes 函数强制在堆上分配。它避免了其他一些可能隐藏此处介绍的字符串优化的编译器优化。

在此示例中,转换仅用于switch比较,而Go可以避免转换,因为它只需要比较实际内容即可。Go实际上通过删除转换并直接指向背后的字节数组来优化代码:

125651eb46445d9acc71d84f0cec989f.png

我们还可以看到生成的程序汇编的确切优化:

a83a6cc86ee083ba5ca4041dd4193a29.png

Go直接在比较中使用返回的字节。它首先检查字节数组和case中字符串的长度然后再检查字符串本身。在switch之外进行字符串赋值将导致内存分配,因为编译器将不知道稍后在何处使用该字符串。

其他优化

switch 中并不是唯一适用于转换优化的情况。Go编译器同时将此行为应用于其他情况,例如:

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

b22f4f0a489ac95012707ff1a6854ae4.png

访问map时,实际上不需要进行任何转换即可加快访问速度。

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

09c84e99402b245d9d0e9df5f727ec5c.png

这种情况和switch类似。它首先比较字符串和字节数组的长度,然后对比字符串。

编译整理自 Go: String & Conversion Optimization

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

9b54e3ec440b2e0dac1f1a4f4f12f06f.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值