Go 性能加速器:你需要知道的 5 个诀窍和技巧

👇我在这儿 

通过这 5个诀窍和技巧来将那些运行缓慢,低效的 go 代码变成精简,高效,快速的机器代码。

各位 Go 大师和初学者们,你们是否已经厌倦了那些慢得让你想要抓狂的 Go 应用程序?

别担心,我们有解决方案。 

在这篇文章中,我将分享将 Go 应用程序变成精简、高效的前5个诀窍和技巧。 

所以拿杯咖啡,放松一下,准备把你的 Go 技能提升到更高的水平。

321ac53af2c2b087ef4be4c0908c8381.png

1. 避免使用反射

反射是 Go 中一个强大的特性,它允许程序在运行时自我检查和修改自身的结构和行为。 

你可以使用反射来确定一个值的类型,访问其字段,并调用其方法:

package mainimport ("fmt""reflect"
)
// 通过反射来获取 x 的类型
func main() {x := 100v := reflect.ValueOf(x)t := v.Type()fmt.Println("Type:", t)
}

但是! 反射是在运行时进行值的自我检查和操作,而不是编译时。 

Go运行时必须执行额外的工作来确定反射值的类型和结构,这可能会增加开销并减慢程序速度。 

反射还会使代码更难以阅读和理解而使影响生产力受到影响。

2. 避免使用字符串拼接

通常使用 bytes.Buffer 类型来构建字符串比使用 + 操作符连接字符串更有效率。

看看这个性能较差的代码:

s := ""
for i := 0; i < 100000; i++ {s += "x"
}
fmt.Println(s)

这段代码每次循环都会创建一个新的字符串,这会使效率低下且导致性能变差。

相反地,你可以使用 bytes.Buffer 更高效地构建字符串:

// 使用 bytes.Buffer 来构建字符串
var buffer bytes.Buffer
for i := 0; i < 100000; i++ {buffer.WriteString("x")
}
s := buffer.String()
fmt.Println(s)

另一个解决方案是使用 strings.Builder

它的用法类似于 bytes.Buffer,但提供更好的性能:

// 使用 strings.Builder 来构建字符串
var builder strings.Builderfor i := 0; i < 100000; i++ {builder.WriteString("x")
}
s := builder.String()
fmt.Println(s)

以下是基础测试

我已经比较了这两种解决方案,结果如下:

  • 使用 bytes.Buffer 比使用字符串拼接快得多,在某些情况下性能提升超过 250 倍

  • 使用 strings.Builder 大约比 bytes.Buffer 快1.5倍

需要注意的是,实际的性能提升可能因为特定的 CPU 和代码运行环境等因素而有所差异。

strings.Builder比bytes.Buffer更快的原因有几个

这是因为 strings.Builder 专门针对字符串的构建进行了优化。

相比之下,bytes.Buffer 是一个更通用的缓冲区,可以用于构建任何类型的数据,但它可能没有像 strings.Builder 那样专门优化字符串构建的性能。

3. 预分配切片和 map 的空间

在Go中,为预期容纳的元素数量适当分配切片的容量可以提高性能。

这是因为分配具有更大容量的切片可以减少在添加元素时需要调整切片大小的次数。

下面是压力测试:

func main() {start := time.Now()s := make([]int, 0, 10)for i := 0; i < 100000; i++ {s = append(s, i)}elapsed := time.Since(start)fmt.Printf("Allocating slice with small capacity: %v\n", elapsed)start = time.Now()s = make([]int, 0, 100000)for i := 0; i < 100000; i++ {s = append(s, i)}elapsed = time.Since(start)fmt.Printf("Allocating slice with larger capacity: %v\n", elapsed)
}

是的,通过预分配,我们能够将速度提升3倍。

我已经在一篇关于切片的文章中对于为什么预分配更快[1]写了一个详细的解释,你可以通过文末的链接查看。

4. 避免使用只有一个具体类型的接口

如果你知道一个接口只会有一个具体类型,你可以直接使用该具体类型,以避免接口的开销。

直接使用具体类型可以比使用接口更高效,因为它避免了在接口中存储类型和值的开销。

这里有一个例子,比较了在 Go 中使用接口和直接使用具体类型的性能:

func main() {start := time.Now()var s Shape = &Circle{radius: 10}for i := 0; i < 100000; i++ {s.Area()}elapsed := time.Since(start)fmt.Printf("Using Shape interface: %s\n", elapsed)start = time.Now()c := Circle{radius: 10}for i := 0; i < 100000; i++ {c.Area()}elapsed = time.Since(start)fmt.Printf("Using Circle type directly: %s\n", elapsed)
}

使用接口的耗时为358微秒,而使用具体类型的耗时为342微秒。

需要注意的是,只有当你确信一个接口只会有一个具体类型时,才应该使用这种技术。

5. 使用 go vet

govet 工具是一种静态分析工具,它可以在不运行代码的情况下帮助你找到 Go 代码中可能存在的问题。

govet 检查您的代码以查找可能导致错误或性能问题的各种问题。它就像是一个代码质量警察,不断检查以确保你没有犯任何低级错误。

要使用 govet,可以运行 go tool vet 命令,并将要检查的 Go 源文件的名称作为参数传递:

go tool vet main.go

你也可以在 go tool vet 命令中加入 -all 标志,以检查当前目录及其子目录中的所有 Go 源文件:

go tool vet -all

govet 可能会不断地报告不需要报告的问题。

你可以通过在代码中编写 "vet comments" 来自定义 govet 的行为。Vet 注释是特殊的注释,告诉 govet 忽略某些问题或检查其他问题。

以下是一个 vet 注释的例子,告诉 govet 忽略未使用的变量:

func main() {var x int//go:noinline_ = x
}

总结:

记得要密切关注内存分配、接口、预分配等问题。如果你想将你的 Go 代码提升到更高的水平,还有很多其他的技巧和窍门可以探索。

只要保持学习的态度,并享受编程的乐趣,就可以了!祝编程愉快!

相关链接:

[1]https://medium.com/@func25/go-secret-slice-a-deep-dive-into-slice-6bd7b0b70ec4

原文地址:

https://medium.com/@func25/go-performance-boosters-the-top-5-tips-and-tricks-you-need-to-know-e5cf6e5bc683

原文作者:

Aiden (@func25)

本文永久链接:https://github.com/gocn/translator/blob/master/2023/w12_Go_Performance_Boosters_The_Top_5_Tips_and_Tricks_You_Need_to_Know.md

译者:小超人

校对:Jesse


7514e209a131d68b95125191cf4a32ce.jpeg

Ding! 您有一份参会邀请待查收👇

查看全文

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dgrt.cn/a/2225814.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章:

7514e209a131d68b95125191cf4a32ce.jpeg

Go 性能加速器:你需要知道的 5 个诀窍和技巧

👇我在这儿 通过这 5个诀窍和技巧来将那些运行缓慢,低效的 go 代码变成精简,高效,快速的机器代码。各位 Go 大师和初学者们,你们是否已经厌倦了那些慢得让你想要抓狂的 Go 应用程序?别担心,我们……

【AIGC提示词工程师、AI提示词工程师、Prompts工程师、Midjourney培训】电商行业AIGC图像生成与内容创作学习路线图

导言 关注【元壤教育】公众号进入平台开始系统学习之路。 AIGC(Stable Diffusion、DALL-E 和 Midjourney)助力电商行业降本增效、提升10倍生产力 一门深入全面的课程,专为对AI图像生成在电商行业应用感兴趣的人士打造,旨在帮助他们……

记录一个问题,内存泄漏,还没彻底解决

记录一个问题,内存泄漏,还没彻底解决…

IO流中「线程」模型总结

IO流模块:经常看、经常用、经常忘; 一、基础简介
在IO流的网络模型中,以常见的「客户端-服务端」交互场景为例; 客户端与服务端进行通信「交互」,可能是同步或者异步,服务端进行「流」处理时,可……

PACS系统源码:CT后处理技术之仿真内镜CTVE

仿真内窥镜VE
VE是利用医学影像作为原始数据,融合图像处理、计算机图形学、科学计算可视化、虚拟现实技术,模拟传统光学内镜的一种技术。
又叫做腔内重建技术,是指调整CT阈值及组织透明度即可获得组织三维伪彩背景图像。 优点: ……

kafka之一—-概念结构

https://kafka.apache.org/ https://blog.csdn.net/liuyu973971883/article/details/109036572 https://blog.csdn.net/u013256816/article/details/80300225
1、概念
Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量……

用Python写一个BMI计算代码

有粉丝问我怎么写一个BMI算法,安排 height float(input("请输入身高(米): ")) weight float(input("请输入体重(千克): "))
计算BMI
bmi weight / (height ** 2)
显示结果
print("您的……

Postgre SQL pgsql解决表死锁解锁

问题描述 对表进行范围更新,导致表锁死,业务系统瘫痪 解决办法 –查询是否锁表了
select oid from pg_class where relname可能锁表了的表
–pid 是进程
select pid from pg_locks where relation上面查出的oid
–如果查询到了结果,表示该表被锁 则需要释放锁定
sel……

如何优雅的实现接口防刷,看过来!!!

在我们的app、网站等互联网应用系统中,如果接口直接暴露在外网下,是存在着接口安全问题的。当我们的接口没有任何防刷的措施,就相当于在互联网上裸奔一样!当被一些不怀好意的人利用,那就是发生灾难的时候了&#xff01……

vba:Comment 对象,批注

Comment 对象 代表单元格批注 批注添加
Sub 批注添加() With [a1] If .Comment Is Nothing Then .AddComment.Text "123" .Comment.Visible = True End If End With End Sub
Sub 删除批注() For Each Rng In Selection If N……

【面试题 高逼格利用 类实现加法】编写代码, 实现多线程数组求和.

编写代码, 实现多线程数组求和.关键1. 数组的初始化关键2. 奇偶的相加import java.util.Random;public class Thread_2533 {public static void main(String[] args) throws InterruptedException {// 记录开始时间long start System.currentTimeMillis();// 1. 给定一个很长的……

一个python训练

美国:28:麻省理工学院,斯坦福大学,哈佛大学,加州理工学院,芝加哥大学,普林斯顿大学,宾夕法尼亚大学,耶鲁大学,康奈尔大学,哥伦比亚大学,密歇根大学安娜堡分校,约翰霍普金斯大学,西北大学,加州大学伯克利分校,纽约大学,加州大学洛杉矶分校,杜克大学,卡内基梅隆大学,加州大学圣地……

Mybatis03学习笔记

目录 使用注解开发
设置事务自动提交
mybatis运行原理
注解CRUD
lombok使用(偷懒神器,大神都不建议使用)
复杂查询环境(多对一)
复杂查询环境(一对多)
动态sql环境搭建
动态sql常用标签……

设置或取得c# NumericUpDown 编辑框值的方法,(注意:不是Value值)

本人在C#开发中使用到了NumericUpDown控件,但是发现该控件不能直接控制显示值,经研究得到下面的解决办法
NumericUpDown由于是由多个控件组合而来的控件,其中包含一个类似TextBox的控件,若想取得或改变其中的值要使用如下方法
N……

使用NPOI 技术 的SetColumnWidth 精确控制列宽不能成功的解决办法(C#)

在使用NPOI技术开发自动操作EXCEL软件时遇到不能精确设置列宽的问题。

ISheet sheet1 hssfworkbook.CreateSheet("Sheet1");
sheet1.SetColumnWidth(0, 50 * 256); // 在EXCEL文档中实际列宽为49.29
sheet1.SetColumnWidth(1, 100 * 256); // 在EXCEL文……

Mysql 数据库zip版安装时basedir datadir 路径设置问题,避免转义符的影响

本人在开发Mysql数据库自动安装程序时遇到个很奇怪的问题,其中my.ini的basedir 的路径设置是下面这样的:
basedir d:\测试\test\mysql
但是在使用mysqld安装mysql服务时老是启动不了,报1067错误,后来查看window事件发现一个独特……

java stream sorted排序 考虑null值

项目里使用到排序, java里没有像C# 里的linq,只有stream,查找stream.sorted源码看到有个
Comparator.nullsLast
然后看了一下实现,果然是能够处理null值的排序,如:minPriceList.stream().sorted(Comparator.comparing(l -> l.g……

spring @EnableConfigurationProperties 实现原理

查看DataSourceAutoConfiguration源码,发现如下代码: Configuration ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) EnableConfigurationProperties(DataSourceProperties.class) Import({ DataSourcePoolMetadataProvidersCon……

postman请求https网址没有响应,但是用浏览器有响应,解决办法

遇到个问题:同一个get请求的url,postman请求https网址没有响应,但是用浏览器有响应
url是https开头的,查看错误描述里有一个SSL的选项: 然后根据描述关掉这个选项: 然后就没问题了,能正常请求及……

java @Inherited注解的作用

看到很多注解都被Inherited进行了修饰,但是这个Inherited有什么作用呢?
查看Inherited代码描述:
Indicates that an annotation type is automatically inherited. If an Inherited meta-annotation is present on an annotation type decl……

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注