Go编程规范和性能调优(三)——规范编码和性能优化

news2024/10/5 21:17:36

文章目录

    • 一、本次学习重点内容:
    • 二、详细知识点介绍:
      • 1、高质量编程简介
        • 什么是高质量?
        • 编程原则:
      • 2、编码规范
        • 注释:
        • 代码格式:
        • 命名规范
          • 变量:
          • 函数:
          • package:
          • 错误和异常处理:
          • 错误的Wrap和 Unwrap:
          • 错误判定:
      • 3、性能优化简介
        • 简介
      • 4、性能优化建议
        • BenchMark——性能测试
        • Slice——预分配内存
          • 切片:
          • 陷阱——大内存为释放
        • map——预分配内存
        • 字符串处理
          • 1、string拼接
          • 2、strings.Builder
          • 3、byteBuffer
          • 性能测试:
        • 空结构体
          • 测试:
          • 结果:
        • Atomic包
          • 测试:
          • 结果:
    • 三、个人总结:

一、本次学习重点内容:

  • 本次学习的知识要点有哪些?

    1、高质量编程

    高质量编程简介

    编码规范
    性能优化建议

    2、性能调优实战

    性能调优简介
    性能优化基础指南

二、详细知识点介绍:

1、高质量编程简介

什么是高质量?

编写的代码能够达到正确可靠、简洁清晰的目标可称之为高质量代码。

各种边界条件是否考虑完备

异常情况处理

稳定性保证易读易维护

编程原则:

1、简单性
消除“多余的复杂性”,以简单清晰的逻辑编写代码。

不理解的代码无法修复改进。

2、可读性
代码是写给人看的,而不是机器。

编写可维护代码的第一步是确保代码可读。

3、生产力
团队整体工作效率非常重要。

2、编码规范

注释:

公共符号始终要注释

包中声明的每个公共的符号:变量、常量、函数以及结构都需要添加注释。

任何既不明显也不简短的公共功能必须予以注释。

无论长度或复杂程度如何,对库中的任何函数都必须进行注释。

代码格式:

推荐使用gofmt自动格式化代码

1、gofmt

Go语言官方提供的工具,能自动格式化Go语言代码为官方统一风格,常见IDE都支持方便的配置。

2、goimports

也是Go语言官方提供的工具,实际等于gofmt 加上依赖包管理。

自动增删依赖的包引用、将依赖包按字母序排序并分类。

命名规范

变量:

1、简洁胜于冗长

2、缩略词全大写,但当其位于变量开头且不需要导出时,使用全小写。

例如使用ServeHTTP而不是 ServeHttp

使用XMLHTTPRequest 或者xmlHTTPRequest

2、变量距离其被使用的地方越远,则需要携带越多的上下文信息。

全局变量在其名字中需要更多的上下文信息,使得在不同地方可以轻易辨认出其含义

函数:

1、函数名不携带包名的上下文信息,因为包名和函数名总是成对出现的

2、函数名尽量简短

3、当名为foo 的包某个函数返回类型Foo时,可以省略类型信息而不导致歧义

4、当名为foo的包某个函数返回类型T时(T并不是Foo),可以在函数名中加入类型信息

package:

1、只由小写字母组成。

2、不包含大写字母和下划线等字符简短并包含一定的上下文信息。例如schema、task等。

3、不要与标准库同名。例如不要使用sync或者strings。

以下规则尽量满足,以标准库包名为例:

不使用常用变量名作为包名。例如使用bufio而不是buf

使用单数而不是复数。例如使用encoding而不是encodings

谨慎地使用缩写。例如使用fmt在不破坏上下文的情况下比 format更加简短

错误和异常处理:

简单错误:

1、简单的错误指的是仅出现一次的错误,且在其他地方不需要捕获该错误。

2、优先使用errors.New 来创建匿名变量来直接表示简单错误。

3、如果有格式化的需求,使用 fmt.Errorf。

错误的Wrap和 Unwrap:

1、错误的Wrap 实际上是提供了一个error 嵌套另一个error的能力,从而生成一个 error的跟踪链。

2、在fmt.Errorf中使用: %w关键字来将一个错误关联至错误链中。

错误判定:

1、判定一个错误是否为特定错误,使用errors.ls

2、不同于使用==,使用该方法可以判定错误链上的所有错误是否含有特定的错误

3、在错误链上获取特定种类的错误,使用errors.As

3、性能优化简介

简介

1、性能优化的前提是满足正确可靠、简洁清晰等质量因素

2、性能优化是综合评估,有时候时间效率和空间效率可能对立

3、针对 Go语言特性,介绍Go相关的性能优化建议

4、性能优化建议

BenchMark——性能测试

性能表现需要实际数据衡量

Go语言提供了支持基准性能测试的benchmark工具

使用方式:

go test -bench=.-benchmem

测试函数:

func BenchmarkPlus(b *testing.B) {
   b.ReportAllocs()
   for i := 0; i < b.N; i++ {
      //Plus(10, "ok")
   }
}

结果:

image-20230203160449412

Slice——预分配内存

尽可能使用make()初始化切片时的容量信息。(扩容需要消耗性能)

切片:
image-20230203160946079

切片本质是一个数组片段的描述。

包括数组指针

片段的长度

片段的容量(不改变内存分配情况下的最大长度)

切片操作并不复制切片指向的元素,而是创建一个新的切片会复用原来切片的底层数组。

陷阱——大内存为释放

在已有切片基础上创建切片,不会创建新的底层数组场景。(会创建引用)

·原切片较大,代码在原切片基础上新建小切片

·原底层数组在内存中有引用,得不到释放

可使用copy替代re-slice。

map——预分配内存

原因:

1、不断向map中添加元素的操作会触发map 的扩容

2、提前分配好空间可以减少内存拷贝和 Rehash的消耗

3、建议根据实际需求提前预估好需要的空间

字符串处理

1、string拼接
func Plus(n int, str string) string {
   s := ""
   for i := 0; i < n; i++ {
      s += str
   }
   return s
}
2、strings.Builder
func StrBuilder(n int, str string) string {
   var builder strings.Builder
   for i := 0; i < n; i++ {
      builder.WriteString(str)
   }
   return builder.String()
}
3、byteBuffer
func ByteBuffer(n int, str string) string {
   buf := new(bytes.Buffer)
   for i := 0; i < n; i++ {
      buf.WriteString(str)
   }
   return buf.String()
}
性能测试:
package 性能测试

import "testing"

func BenchmarkPlus(b *testing.B) {
   b.ReportAllocs()
   for i := 0; i < b.N; i++ {
      Plus(10, "ok")
   }
}
func BenchmarkStrBuilder(b *testing.B) {
   b.ReportAllocs()
   for i := 0; i < b.N; i++ {
      StrBuilder(10, "ok")
   }
}
func BenchmarkByteBuffer(b *testing.B) {
   b.ReportAllocs()
   for i := 0; i < b.N; i++ {
      ByteBuffer(10, "ok")
   }
}

结果:

image-20230203173648921

运行时间和内存占用上strings.Builder明显优于其他两个。

使用+拼接性能最差,strings.Builder,bytes.Buffer相近,strings.Buffer更快

分析:

字符串在Go语言中是不可变类型,占用内存大小是固定的,使用+每次都会重新分配内存。

strings.Builder,bytes.Buffer底层都是[]byte数组,内存扩容策略,不需要每次拼接重新分配内存。

空结构体

使用空结构体节省内存

空结构体struct实例不占据任何的内存空间可作为各种场景下的占位符使用

1、节省资源

2、空结构体本身具备很强的语义,即这里不需要任何值,仅作为占位符

测试:

Demo.go:

package 性能测试

func EmptyStructMap(n int) {
   m := make(map[int]struct{})
   for i := 0; i < n; i++ {
      m[i] = struct{}{}
   }
}
func BoolMap(n int) {
   m := make(map[int]bool)
   for i := 0; i < n; i++ {
      m[i] = false
   }
}

Demo_test.go:

package 性能测试

import "testing"

func BenchmarkEmptyStructMap(b *testing.B) {
   b.ReportAllocs()
   for i := 0; i < b.N; i++ {
      EmptyStructMap(10)
   }
}
func BenchmarkBoolMap(b *testing.B) {
   b.ReportAllocs()
   for i := 0; i < b.N; i++ {
      BoolMap(10)
   }
}
结果:

image-20230203175303989

可以看到空就结构体更节省内存

Atomic包

测试:

Demo.go

package 性能测试

import (
   "sync"
   "sync/atomic"
)

type atomicCounter struct {
   i int32
}

func AtomicAddOne(c *atomicCounter) {
   atomic.AddInt32(&c.i, 1)
}

type mutexCounter struct {
   i int32
   m sync.Mutex
}

func MutexAddOne(c *mutexCounter) {
   c.m.Lock()
   c.i++
   c.m.Unlock()
}

Demo_test.go

package 性能测试

import "testing"

func BenchmarkAtomicAddOne(b *testing.B) {
   b.ReportAllocs()
   a := atomicCounter{0}
   for i := 0; i < b.N; i++ {
      AtomicAddOne(&a)
   }
   b.Log(a.i)
}
func BenchmarkMutexAddOne(b *testing.B) {
   b.ReportAllocs()
   a := mutexCounter{}
   for i := 0; i < b.N; i++ {
      MutexAddOne(&a)
   }
   b.Log(a.i)
}
结果:

image-20230203180956739

可以看到使用了Atomic包比使用锁快了8倍左右。

原因:

锁的实现是通过操作系统来实现,属于系统调用

atomic操作是通过硬件实现,效率比锁高

建议:

sync.Mutex应该用来保护一段逻辑,不仅仅用于保护一个变量

对于非数值操作,可以使用atomic.Value,能承载一个interface

三、个人总结:

本次学习内存包括go中的编码规范和基础性能优化。编码规范很重要,好的修改才能写出通俗易懂的代码,才能更好的构建一个个大型项目。性能优化方面避免常见的性能陷阱可以保证大部分程序的性能普通应用代码,不要一味地追求程序的性能越高级的性能优化手段越容易出现问题在满足正确可靠、简洁清晰的质量要求的前提下提高程序性能。

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

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

相关文章

关于yolov8的训练的一些改动

1、YOLOv8创新改进点&#xff1a; 1.1.Backbone 使用的依旧是CSP的思想&#xff0c;不过YOLOv5中的C3模块被替换成了C2f模块&#xff0c;实现了进一步的轻量化&#xff0c;同时YOLOv8依旧使用了YOLOv5等架构中使用的SPPF模块&#xff1b; 1.2.PAN-FPN 毫无疑问YOLOv8依旧使…

大文件传输软件的优势有哪些?-镭速传输

互联网时代&#xff0c;大数据传输是企业面临的必不可免的问题&#xff0c;可以选择传统的FTP、网盘等方式来传输&#xff0c;对于小型文件或许是有优势的&#xff1b;但是对于大型文件数据的话&#xff0c;也许会出现传输速度慢&#xff0c;数据不可靠的情况&#xff0c;极大的…

python3+requests+unittest:接口自动化测试(一)

简单介绍框架的实现逻辑&#xff0c;参考代码的git地址&#xff1a; GitHub - zhangying123456/python_unittest_interface: pythonunittest接口自动化测试脚本 1.环境准备 python3 pycharm编辑器 2.框架目录展示 &#xff08;该套代码只是简单入门&#xff0c;有兴趣的可…

Nginx——Keepalived的原理与配置

摘要 Keepalived的作用是检测服务器的状态&#xff0c;如果有一台web服务器宕机&#xff0c;或工作出现故障&#xff0c;Keepalived将检测到&#xff0c;并将有故障的服务器从系统中剔除&#xff0c; 同时使用其他服务器代替该服务器的工作&#xff0c;当服务器工作正常后Keep…

python求解带约束的优化问题

带约束的优化问题可被定义为&#xff1a; 在python中&#xff0c;可以使用scipy的optimize包进行求解&#xff0c;具体求解函数为linprog&#xff0c;下面举例说明求解方法&#xff1a; 假设问题被定义为&#xff1a; 首先&#xff0c;求解最大值问题&#xff0c;我们可以通…

Spring Security 源码解读 :认证总览

Spring Security 提供如下几种认证机制&#xff1a; Username & PasswordOAuth2.0 LoginSAML 2.0 LoginRemember MeJAAS AuthenticationPre-authentication ScenariosX509 Authentication 这里使用Spring Boot 2.7.4版本&#xff0c;对应Spring Security 5.7.3版本 Serv…

LeetCode题目笔记——1588. 所有奇数长度子数组的和

文章目录题目描述题目难度——简单方法一&#xff1a;暴力代码/C代码/Python方法二&#xff1a;前缀和代码/C代码/Python总结题目描述 给你一个正整数数组 arr &#xff0c;请你计算所有可能的奇数长度子数组的和。 子数组 定义为原数组中的一个连续子序列。 请你返回 arr 中…

MySql性能优化(六)索引监控

文章目录索引监控Handler_read_firstHandler_read_keyHandler_read_lastHandler_read_nextHandler_read_prevHandler_read_rndHandler_read_rnd_next索引监控 SHOW STATUS LIKE Handler_read%解释一下各个参数的含义 Handler_read_first 通过index获取数据的次数 Handler_r…

在cmd中遍历局域网内的IP命令解析

简单的方法 1&#xff0c;直接通过浏览器访问路由器&#xff0c;通过路由器的页面查看。2&#xff0c;网络中很多扫描网络的软件&#xff0c;3&#xff0c;自己使用cmd命令查看 有时候自己也觉得&#xff0c;有简单的方式还用这麻烦的干嘛。但遇到不知道路由的登录密码呢&…

Djiango零基础-快速了解基本框架笔记-附案例

初识Djiango 1. 安装djiango pip install django4.1 -i https://mirrors.aliyun.com/pypi/simple/C:\python38- python.exe- Scripts- pip.exe- djiango-admin.exe 【工具&#xff0c;创建djiango项目】- Lib- 内置模块- site-packages- openpyxl- python-docx- flask- djia…

IPV6实验(2.3)

目标&#xff1a; 一、首先将r2、r3、r4这个公网先弄通 [r2]int gi 0/0/0 [r2-GigabitEthernet0/0/0]ip add 23.1.1.1 24 [r3]int gi 0/0/0 [r3-GigabitEthernet0/0/0]ip add 23.1.1.2 24 [r3-GigabitEthernet0/0/0]int gi 0/0/1 [r3-GigabitEthernet0/0/1]ip add 34.1.1.1 2…

YOLO的学习

如何评价Alexey Bochkovskiy团队提出的YoloV7&#xff1f; - 知乎 1, Selective Search&#xff0c;RCNN和FasterRCNN 机器视觉(CV) 超简指南 选择性搜索 Selective Search_哔哩哔哩_bilibili 【精读RCNN】03选择性搜索&#xff0c;selective search_哔哩哔哩_bilibili …

win10系统安装

系统安装 文章目录系统安装1.工具下载2.制作启动盘3. win 10镜像下载4.进入PE系统1.工具下载 需要准备一个至少16 GB的U盘&#xff0c;工具下载链接 U盘&#xff1a;https://share.weiyun.com/aHhPh16e 迅雷&#xff1a;https://dl.xunlei.com/ win 10 镜像链接&#xff1a…

大咖说·计算讲谈社|当我们在谈目标时,究竟在谈什么?

本讲内容&#xff0c;节选自阿里巴巴研究员吴翰清&#xff08;道哥&#xff09;面向团队的内部讲话&#xff0c;经删减整理后&#xff0c;作为【计算讲谈社】第十六讲公开分享。 讲师介绍 吴翰清&#xff08;道哥&#xff09;&#xff1a;阿里巴巴研究员&#xff0c;阿里巴巴、…

33复杂美,上链不复杂

“链上复杂美&#xff0c;上链不复杂。” 33复杂美座落在美丽的西子湖畔&#xff1a;杭州&#xff0c;并在上海、南京、宁波、海南皆有设立分部。公司员工超过100人&#xff0c;70%为技术人员&#xff0c;吸引了来自甲骨文、阿里等优秀人才加盟。复杂美为浙江省区块链技术应用协…

windows 编译telegram桌面客户端

目的 主要是为了研究一下人家的软件架构。 步骤 前置条件 梯子至少10G硬盘空间 安装第三方应用 请更新至最新版。 GITCmakePython3visual studio 2022Qt Visual Studio Tools: Open Extensions -> Manage Extensions Go to Online tab Search for Qt Install Qt Visu…

系统学习Python——2D绘图库Matplotlib:绘图函数matplotlib.pyplot.plot

分类目录&#xff1a;《系统学习Python》总目录 matplotlib.pyplot是Matplotlib的基于状态的接口。它提供了一种隐式的、类似MATLAB的绘图方式。它还会在您的屏幕上打开图形&#xff0c;并充当图形GUI管理器。 语法 matplotlib.pyplot.plot(*args, scalexTrue, scaleyTrue , …

威联通NAS共享文件夹挂载到linux服务器下

威联通虚机中centos挂载共享文件夹设置方法 1、登录到QTS。 2、控制台–>Win/Mac/NFS选项&#xff0c;在Linux NFS中开启NFS v3或NFSv4服务。 3、设置文件夹权限&#xff1a; 控制台–>共享文件夹中&#xff0c;找到需要共享的文件夹&#xff0c;编辑文件夹权限。 选…

Golang数据竟态

本文以一个简单事例的多种解决方案作为引子&#xff0c;用结构体Demo来总结各种并发读写的情况 一个数据竟态的case package mainimport ("fmt""testing""time" )func Test(t *testing.T) {fmt.Print("getNum(): ")for i : 0; i <…

「Python|场景案例」如何将多个视频合并成多个子画面并排的单个视频?

本文主要介绍如何将多个视频画面合并到一个视频中&#xff0c;使得合成后的视频画面是原视频的并排画面。 文章目录场景描述准备工作处理步骤源代码处理效果展示场景描述 在某些音视频剪辑的场景下我们希望一个视频画面显示多个子画面&#xff0c;比如&#xff1a; 乐器演奏视…