这是一篇后端实践的文章,本文阐述了高质量编程与性能调优实战,其中包括了图片优化、前端资源优化、数据请求优化等,通过实战和测试,分析和优化任意项目中存在的性能问题。
本人能力有限,有写的不对的地方还请大家指出,十分感谢!
一、高质量编程
1.1 何为高质量
高质量是指编写的代码正确可靠、简洁清晰
正确:是否考虑到边界条件,错误调用是否能正确处理,预期意外的输入是否处理
可靠:错误、异常能否处理
简洁清晰:易读易维护,实现功能时逻辑简单,团队合作更容易
编程原则:简单性、可读性、生产力
1.2 如何编写高质量代码
1.2.1 编码规范:代码格式
推荐使用gofmt自动格式化代码,这是官方提供的工具,自动格式化成官方统一风格,常见IDE都支持配置
还可以使用goimports ,也是官方提供的工具,不光可是实现自动格式化,还可以对依赖包进行管理,自动增删依赖包的引用,将依赖包按照字母顺序排序和分类。
1.2.2 编码规范:注释
1.公共符号始终要注释
(1)包中声明的每个公共符号:变量、常量、桉树、结构体都要加注释
(2)任何不明显也不简短的公共功能都必须予以注释
(3)无论长度、复杂程度,库中的任何函数都必须注释
不需要注释实现接口的方法,对于阅读代码没有帮助,可以直接删除(如果一段注释只是提示我们要去阅读另外的文档,那么对于阅读代码没有任何的帮助)
注释应该解释代码作用,解释代码是如何做的(对于复杂并不明显的逻辑进行解释),解释实现代码的原因,解释代码在什么时候会出错,一些限制条件
注意:有时更新了代码但是没有更新注释,因此可能是不同的执行逻辑,要以代码为准;
注释应该写出代码中没有表达的上下文信息,方便后续评估、维护
1.2.3 编码规范:命名规范
(1)变量命名:
简洁;若使用的位置和声明的位置较远,全局变量的名字最好带有更多的上下文信息;
缩略词全大写,若位于开头且不需要导出,用小写
eg: ServeHTTP ,不是ServeHttp
XMLHTTPRequest 或者xmlHTTPRequest
(2)函数命名:
简洁;不包含包名的上下文信息;
当函数返回类型和包名一样时,可以省略;不一样时需要在函数名中加入类型信息
(golang是http包)
二、性能调优
2.1 图片优化
在实际的Web开发中,图片优化是一种常见的性能瓶颈,常见的优化图片性能的操作如下:
- 图片压缩:使用图片压缩工具减小文件大小,文件过大时加载速度会很慢,影响用户体验。
- 图片格式选择:如选择JPEG格式、PNG格式、WebP格式,要根据不同情景进行选择
- 响应式图片
具体的实现方法如下:
(1)使用第三方库实现
最常用的是以下两个库:github.com/nfnt/resize
github.com/disintegration/imaging
使用该方法需要保证已经安装了有关的第三方库,这两个库可以实现图像的压缩、旋转、尺寸修改等操作
eg:使用第一个库对图像进行缩放操作:
package main
import (
"image"
"image/jpeg"
"os"
"github.com/nfnt/resize"
)
func main() {
inputFile, _ := os.Open("input.jpg")
defer inputFile.Close()
img, _, _ := image.Decode(inputFile)
newImg := resize.Resize(300, 0, img, resize.Lanczos3)
outputFile, _ := os.Create("output.jpg")
defer outputFile.Close()
jpeg.Encode(outputFile, newImg, nil)
}
(2)使用原生库实现
对于图片的优化也可不使用第三方库,go语言的标准库中提供了image、image/jpeg等包,同样具有对图片的处理功能,如对图片编码解码等。
以下代码是对图像进行缩放的实例
package main
import (
"image"
"image/jpeg"
"os"
)
func main() {
inputFile, _ := os.Open("input.jpg")
defer inputFile.Close()
img, _, _ := image.Decode(inputFile)
newWidth := 300
newHeight := 0 // Maintain aspect ratio
newImg := image.NewRGBA(image.Rect(0, 0, newWidth, newHeight))
draw.CatmullRom.Scale(newImg, newImg.Bounds(), img, img.Bounds(), draw.Over, nil)
outputFile, _ := os.Create("output.jpg")
defer outputFile.Close()
jpeg.Encode(outputFile, newImg, nil)
}
(3)使用命令行工具
对图像实现更复杂的优化操作,比如批量处理,就需要使用os/exec包,它可以调用如ImageMagic 、GraphicsMagick等图像处理软件的命令行工具,使用该方法需要保证已经安装了图像处理软件
以下代码是使用图像处理软件命令行工具的实例:
package main
import (
"os"
"os/exec"
)
func main() {
inputFile := "input.jpg"
outputFile := "output.jpg"
cmd := exec.Command("convert", inputFile, "-resize", "300x", outputFile)
cmd.Run()
}
2.2 数据请求优化
数据请求优化需要考虑到网络延迟、并发请求、缓存的实现几个方面。
常见的优化数据请求的方法有以下9点,这些方法可以实现优化数据请求,提高性能以及响应速度,要根据具体情况来选择最佳的优化策略。
(1)使用并发请求
在第一讲中, 我们已经知道go是支持并发的,因此我们可以使用goroutines、channels(信道)实现并发操作。代码展示如下:
package main
import (
"fmt"
"net/http"
"sync"
)
func fetchData(url string, wg *sync.WaitGroup) {
defer wg.Done()
resp, err := http.Get(url)
if err != nil {
fmt.Println("Error fetching data:", err)
return
}
defer resp.Body.Close()
// Process the response
}
func main() {
urls := []string{"url1", "url2", "url3"}
var wg sync.WaitGroup
for _, url := range urls {
wg.Add(1)
go fetchData(url, &wg)
}
wg.Wait()
}
(2)连接复用:
连接的复用可以减少每次请求时连接的建立和断开等操作带来的开销,需要使用HTTP/2或Keep-Alive实现TCP连接的重用操作
(3)设置超时时间
设置合理的超时时间,可以有效的避免因为网络问题而导致请求阻塞太久的情况发生
代码展示如下:
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
client := &http.Client{
Timeout: 10 * time.Second,
}
resp, err := client.Get("url")
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
// Process the response
}
(4)使用HTTP连接池
连接池的使用可以减少重复创建和关闭连接。在go中的net/http包已经实现了HTTP连接池的内置
(5)数据缓存
使用频繁的数据可以考虑将其放置在缓存中,这样可以避免重复的请求,有效的提高了相应的速度
(6)分页、批量操作
当要加载的数据量很大时,可以考虑使用分页加载和批量请求操作
(7)压缩和优化数据
可以启用服务器的Gzip压缩,这种压缩方式减少了数据的传输量,可以提高相应的速度,对于响应数据是十分有效的方式
(8)使用CDN
CDN是内容分发网络,若数据请求的主要是静态资源,那么可以使用CDN加速传输速度,降低了服务器的负担
(9)优化的HTTP库的使用
优化过的HTTP库可以提供更好的性能,如
github.com/valyala/fasthttp