Go 官方标准编译器中所做的优化
本文是对#102 Go 官方标准编译器中实现的优化集锦汇总[1] 内容的记录与总结.

优化1-4: 字符串和字节切片之间的转化

1.紧跟range关键字的 从字符串到字节切片的转换;
package main
import (
"fmt"
"strings"
"testing"
)
var cs10086 = strings.Repeat("shuang!", 10086)
func main() {
fmt.Println(testing.AllocsPerRun(1, f)) //0
fmt.Println(testing.AllocsPerRun(1, g)) //1
}
func f() {
for range []byte(cs10086) {
}
}
func g() {
bs := []byte(cs10086)
for range bs {
}
}
f没有开辟内存,g开辟了一次内存.

2.映射元素读取索引语法中被用做键值的 从字节切片到字符串的转换;
package main
import (
"bytes"
"fmt"
"testing"
)
var name = bytes.Repeat([]byte{'x'}, 188)
var m = make(map[string]string, 10)
var s = ""
func main() {
fmt.Println(testing.AllocsPerRun(1, f2)) //0
fmt.Println(testing.AllocsPerRun(1, g2)) //1
fmt.Println(testing.AllocsPerRun(1, h2)) //1
}
func f2() {
s = m[string(name)] // 有效
}
func g2() {
key := string(name)
s = m[key] // 无效
}
func h2() {
m[string(name)] = "Golang" // 无效
}

3.字符串比较表达式中被用做比较值的 从字节切片到字符串的转换
package main
import (
"fmt"
"testing"
)
var x = []byte{1023: 'x'}
var y = []byte{1023: 'y'}
var b bool
func main() {
fmt.Println(testing.AllocsPerRun(1, f3)) //0
fmt.Println(testing.AllocsPerRun(1, g3)) //2
}
func f3() {
b = string(x) != string(y)
}
func g3() {
sx, sy := string(x), string(y)
b = sx == sy
}

4.含 非空字符串常量 的字符串衔接表达式中的 从字节切片到字符串的转换
package main
import (
"fmt"
"testing"
)
var p = []byte{1023: 'p'}
var q = []byte{1023: 'q'}
var str string
func main() {
fmt.Println(testing.AllocsPerRun(1, f4)) //1
fmt.Println(testing.AllocsPerRun(1, g4)) //3
}
func f4() {
str = ("-" + string(p) + string(q))[1:]
}
func g4() {
str = string(p) + string(q)
}

5.[]rune(aString)转换的时间和空间复杂度都是O(n),但len([]rune(aString))中的此转换 不需要开辟内存
Go 1.12引入
package main
import (
"fmt"
"strings"
"testing"
)
var shuang = strings.Repeat("shuang!", 10086)
func main() {
fmt.Println(testing.AllocsPerRun(1, f5)) //0
fmt.Println(testing.AllocsPerRun(1, g5)) //1
}
func f5() {
_ = len([]rune(shuang))
}
func g5() {
_ = len([]byte(shuang)) //未对len([]byte(aString))做优化
}

6.字符串衔接表达式只需开辟一次内存,无论需要衔接多少个字符串
package main
import (
"fmt"
"testing"
)
var h, i, j, k = "Hello", "World", "Let's", "Go"
var str6 string
func main() {
fmt.Println(testing.AllocsPerRun(1, f6)) //1
fmt.Println(testing.AllocsPerRun(1, g6)) //3
}
func f6() {
str6 = h + i + j + k
}
func g6() {
str6 = h + i
str6 += j
str6 += k
}

7.for i := range anArrayOrSlice{anArrayOrSlice[i]} = zeroElement} 形式 将被优化为一个内部的memclr操作
package main
const N = 1024 * 100
var arr [N]int
func clearArray() {
for i := range arr {
arr[i] = 0
}
}
func clearSlice() {
sli := arr[:]
for i := range sli {
sli[i] = 0
}
}
func clearArrayPtr() {
for i := range &arr {
arr[i] = 0
}
}

benchmark:
package main
import (
"testing"
)
func BenchmarkTest1(b *testing.B) {
for i := 0; i < b.N; i++ {
clearArray()
}
}
func BenchmarkTest2(b *testing.B) {
for i := 0; i < b.N; i++ {
clearSlice()
}
}
func BenchmarkTest3(b *testing.B) { //无效
for i := 0; i < b.N; i++ {
clearArrayPtr()
}
}
执行结果:
goos: darwin
goarch: amd64
pkg: xxxx
cpu: Intel(R) Core(TM) i7-8557U CPU @ 1.70GHz
BenchmarkTest1-8 73000 15309 ns/op
BenchmarkTest2-8 76464 15167 ns/op
BenchmarkTest3-8 40194 30096 ns/op
PASS
ok xxxx 4.213s
8.for k = range m {delete(m,k)}形式 将被优化为一个内部的map清空操作

9.尺寸不大于4个原生字(即int),并且字段数不超过4个的结构体值被视为是小尺寸值
package main
type S1 struct {
a int
}
type S2 struct {
a, b int
}
type S3 struct {
a, b, c int
}
type S4 struct {
a, b, c, d int
}
type S5 struct {
a, b, c, d, e int
}
type S6 struct {
a, b, c, d, e, f int
}
var ss1, ss2, ss3, ss4, ss5, ss6 = make([]S1, 1000), make([]S2, 1000), make([]S3, 1000), make([]S4, 1000), make([]S5, 1000), make([]S6, 1000)
var x1, x2, x3, x4, x5, x6 int
benchmark:
package main
import "testing"
func Benchmark_Range1(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, v := range ss1 {
x1 = v.a
}
}
}
func Benchmark_Range2(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, v := range ss2 {
x2 = v.a
}
}
}
func Benchmark_Range3(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, v := range ss3 {
x3 = v.a
}
}
}
func Benchmark_Range4(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, v := range ss4 {
x4 = v.a
}
}
}
func Benchmark_Range5(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, v := range ss5 {
x5 = v.a
}
}
}
func Benchmark_Range6(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, v := range ss6 {
x6 = v.a
}
}
}
执行结果:
goos: darwin
goarch: amd64
pkg: xxxx
cpu: Intel(R) Core(TM) i7-8557U CPU @ 1.70GHz
Benchmark_Range1-8 4759434 248.4 ns/op
Benchmark_Range2-8 3910621 306.0 ns/op
Benchmark_Range3-8 3735921 328.9 ns/op
Benchmark_Range4-8 3677784 325.9 ns/op
Benchmark_Range5-8 814666 1517 ns/op
Benchmark_Range6-8 728656 1568 ns/op
PASS
ok xxxx 8.868s

因为很多一等公民,其底层结构体的元素,都没有超过4个
10.接口值包裹 指针值 比 包裹 其他类型的值 要快
package main
var p, p2 = new([100]int), new([100]int)
var ip interface{}
package main
import "testing"
func Benchmark_PointerAssign(b *testing.B) {
for i := 0; i < b.N; i++ {
p = p2
}
}
func Benchmark_BoxPointer(b *testing.B) {
for i := 0; i < b.N; i++ {
ip = p
}
}
func Benchmark_PointerAssert(b *testing.B) {
for i := 0; i < b.N; i++ {
p = ip.(*[100]int)
}
}
goos: darwin
goarch: amd64
pkg: xxxx
cpu: Intel(R) Core(TM) i7-8557U CPU @ 1.70GHz
Benchmark_PointerAssign-8 1000000000 0.5251 ns/op 0 B/op 0 allocs/op
Benchmark_BoxPointer-8 1000000000 0.5833 ns/op 0 B/op 0 allocs/op
Benchmark_PointerAssert-8 1000000000 0.6418 ns/op 0 B/op 0 allocs/op
PASS
ok xxxx 2.372s


11.接口值包裹 指针值 比 包裹 其他类型的值 要快
Go 1.15新增优化
package main
var x,y = 255,256
var ix,iy interface{}
package main
import "testing"
func Benchmark_x(b *testing.B) {
for i := 0; i < b.N; i++ {
ix = x
}
}
func Benchmark_y(b *testing.B) {
for i := 0; i < b.N; i++ {
iy = y
}
}
goos: darwin
goarch: amd64
pkg: xxxx
cpu: Intel(R) Core(TM) i7-8557U CPU @ 1.70GHz
Benchmark_x-8 565624285 2.033 ns/op 0 B/op 0 allocs/op
Benchmark_y-8 92127024 12.71 ns/op 8 B/op 1 allocs/op
PASS
ok xxxx 2.653s

12.Bounds Check Elimination






参考资料
#102 Go 官方标准编译器中实现的优化集锦汇总: https://www.bilibili.com/video/BV1YZ4y1K7w2
本文由 mdnice 多平台发布
相关文章:

Go 官方标准编译器中所做的优化
本文是对#102 Go 官方标准编译器中实现的优化集锦汇总[1] 内容的记录与总结. 优化1-4: 字符串和字节切片之间的转化 1.紧跟range关键字的 从字符串到字节切片的转换; package mainimport ( "fmt" "strings" "testing")var cs10086 s…...

C语言程序设计——小学生计算机辅助教学系统
题目:小学生计算机辅助教学系统 编写一个程序,帮助小学生学习乘法。然后判断学生输入的答案对错与否,按下列任务要求以循序渐进的方式分别编写对应的程序并调试。 任务1 程序首先随机产生两个1—10之间的正整数,在屏幕上打印出问题…...
SQL自动递增的列恢复至从0开始
在许多数据库管理系统中,当你删除表格中的所有数据时,自动递增的列(也称为自增列、标识列或序列)的计数器通常不会重置为 0。这是出于性能和数据完整性方面的考虑,以避免因删除数据而导致的自增列值冲突。即使你删除了…...
介绍一下CDN
CDN(内容分发网络,Content Delivery Network)是一个由多个服务器组成的分布式网络,它的目的是将内容高效地传送到用户。下面是CDN的工作原理及其主要特点: 内容分发:当用户首次请求某一特定内容时ÿ…...

2023年最新 Github Pages 使用手册
参考:GitHub Pages 快速入门 1、什么是 Github Pages GitHub Pages 是一项静态站点托管服务,它直接从 GitHub 上的仓库获取 HTML、CSS 和 JavaScript 文件,(可选)通过构建过程运行文件,然后发布网站。 可…...

docker 安装 Nginx
1、下载 docker pull nginx:latest 2、本地创建管理目录 mkdir -p /var/docker/nginx/conf mkdir -p /var/docker/nginx/log mkdir -p /var/docker/nginx/html 3、将容器中的相应文件复制到管理目录中 /usr/docker/nginx docker run --name nginx -p 80:80 -d nginxdocke…...

【NLP的python库(01/4) 】: NLTK
一、说明 NLTK是一个复杂的库。自 2009 年以来不断发展,它支持所有经典的 NLP 任务,从标记化、词干提取、词性标记,包括语义索引和依赖关系解析。它还具有一组丰富的附加功能,例如内置语料库,NLP任务的不同模型以及与S…...

Java IDEA Web 项目 1、创建
环境: IEDA 版本:2023.2 JDK:1.8 Tomcat:apache-tomcat-9.0.58 maven:尚未研究 自行完成 IDEA、JDK、Tomcat等安装配置。 创建项目: IDEA -> New Project 选择 Jakarta EE Template:选择…...

leetcode316. 去除重复字母(单调栈 - java)
去除重复字母 题目描述单调栈代码演示进阶优化 上期经典 题目描述 难度 - 中等 leetcode316. 去除重复字母 给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对…...
零散笔记:《Spring实战》Thymeleaf
1、Thymeleaf模板就是增加一些额外元素属性的HTML,这些属性能够指导模板如何渲染request数据。 <p th:test "${message}">placeholder message</p> th我推测是中文的”替换“。 2、th:each,迭代元素集合。 <div th:each &qu…...

WordArt Designer:基于用户驱动与大语言模型的艺术字生成
AIGC推荐 FaceChain人物写真开源项目,支持风格与穿着自定义,登顶github趋势榜首! 前言 本文介绍了一个基于用户驱动,依赖于大型语言模型(LLMs)的艺术字生成框架,WordArt Designer。 该系统包含四个关键模块:LLM引擎、…...

【C进阶】深度剖析数据在内存中的存储
目录 一、数据类型的介绍 1.类型的意义: 2.类型的基本分类 二、整形在内存中的存储 1.原码 反码 补码 2.大小端介绍 3.练习 三、浮点型在内存中的存储 1.一个例子 2.浮点数存储规则 一、数据类型的介绍 前面我们已经学习了基本的内置类型以及他们所占存储…...

TortoiseGit安装
一、安装Git环境 Git-2.42.0-64-bit.exe (访问密码: 1666)https://url48.ctfile.com/f/33868548-924037167-76e273?p1666 二、安装TortoiseGit TortoiseGit-2.14.0.1-64bit.msi (访问密码: 1666)https://url48.ctfile.com/f/33868548-924037173-d395c7?p1666 三、安装T…...

巨人互动|游戏出海游戏出海的趋势如何
随着全球游戏市场的不断扩大和消费者需求的多元化,游戏出海作为游戏行业的重要战略之一,正面临着新的发展趋势。本文小编将讲讲游戏出海的趋势,探讨一下未来游戏出海的发展方向与前景。 巨人互动|游戏出海&2023国内游戏厂商加快“出海”发…...

k8s 安装 istio(二)
3.3 部署服务网格调用链检测工具 Jaeger 部署 Jaeger 服务 kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.16/samples/addons/jaeger.yaml 创建 jaeger-vs.yaml 文件 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata…...

Postman中参数区别及使用说明
一、Params与Body 二者区别在于请求参数在http协议中位置不一样。Params 它会将参数放入url中以?区分以&拼接Body则是将请求参数放在请求体中 后端接受数据: 二、body中不同格式 2.1 multipart/form-data key - value 格式输入,主要特点是可以上…...

基于python+pyqt的opencv汽车分割系统
目录 一、实现和完整UI视频效果展示 主界面: 识别结果界面: 查看分割处理过程图片界面: 二、原理介绍: 加权灰度化 编辑 二值化 滤波降噪处理 锐化处理 边缘特征提取 图像分割 完整演示视频: 完整代码链…...
游戏设计的主要部分
游戏设计的主要部分 介绍 游戏设计是创建有趣、挑战性和令人满足的游戏体验的过程。它涵盖了许多方面,从概念开发到实际实施,以及最终的游戏测试和优化。游戏设计师需要考虑玩家的情感、技能挑战、故事情节、游戏世界等多个要素,以确保游戏…...
架构师成长之路Redis第二篇|Redis配置文件参数讲解
Redis.conf文件 官网Redis文档链接:Redis官网 官网Redis config配置文件参数讲解:https://redis.io/docs/management/config/ Redis.conf参考模板例子 : https://redis.io/docs/management/config-file/ Redis 可以使用内置的默认配置在没有配置文件的情况下启动,但是仅…...

jsp+servlet+mysql阳光网吧管理系统
项目介绍: 本系统使用jspservletmysql开发的阳光网吧管理系统,纯手工敲打,系统管理员和用户角色,功能如下: 管理员:修改个人信息、修改密码;机房类型管理;机房管理;机位…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...

uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!
目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...

rknn toolkit2搭建和推理
安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...
6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙
Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...