• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

7.29技术学习 | 青训营

武飞扬头像
GJul
帮助1

本文侧重于速记和实际操作部分的内容,其他方面可回顾资料

ep5代码规范

这里是看课后的记忆之谈,只是记下了自己认为比较重要且常用的部分,并不全面

format缩写为fmt

注释要说明前后联系

函数命名内不用带包的名字,因为调用 . 说明了包

return 写return即可不用加else

ep6.1克隆 github.com/wolfogre/go… 到本地,保证能够编译运行

克隆到本地

打开Git Bash

git clone https://github.com/wolfogre/go-pprof-practice.git

请注意将 "(github.com/wolfogre/go…)" 替换为实际要克隆的仓库的 URL,并加git 克隆完成后(在文件管理器中可以搜索到了) 克隆到用户目录下的写法

cd go-pprof-practice

若将项目克隆到桌面上(Windows 系统的路径示例)

cd C:\Users\YourUsername\Desktop
git clone https://github.com/wolfogre/go-pprof-practice.git

编译和运行

法一

命令行终端中输入

进入克隆下来的项目目录

cd go-pprof-practice

编译

go build

运行

./go-pprof-practice

法二

对于使用 Make 的项目 当打开git输入以下语句

make -v

G@GJul MINGW64 ~/go-pprof-practice (master) $ make bash: make: command not found 这意味着操作系统(在这里是 Windows,MINGW64 是一个类似于 Linux 的终端模拟器)中没有找到 make 命令。

【win11上安装MinGW最新版gcc12】www.bilibili.com/video/BV1Ld…

bash: make: command not found

MinGW 只提供了名字为 mingw32-make.exe 的执行文件,该文件和 make.exe 功能一样,为了make执行时能找到该文件,复制mingw32-make.exe一份,并将复制文件命名为make.exe

此时

make

与法一中的 go bulid作用相同

ep6.2尝试使用 test 命令,编写并运行简单测试

Add a test - The Go Programming Language

新建一名为greetings的project

greetings目录下创建一个greetings_test.go的文件,一个greetings.go文件

以下是 greetings.go 文件的示例内容:

package greetings

import (
    "errors"
    "fmt"
)

// Hello 函数为给定的名字返回问候消息。
func Hello(name string) (string, error) {
    // 如果没有给定名字,返回一个错误。
    if name == "" {
        return "", errors.New("空名字")
    }

    message := fmt.Sprintf("你好,%s!", name)
    return message, nil
}

greetings_test.go文件中,添加以下代码:

package greetings

import (
    "testing"
    "regexp"
)

// TestHelloName 调用 greetings.Hello 函数,并检查返回值是否有效。
func TestHelloName(t *testing.T) {
    name := "Gladys"
    want := regexp.MustCompile(`\b` name `\b`)
    msg, err := Hello("Gladys")
    if !want.MatchString(msg) || err != nil {
        t.Fatalf(`Hello("Gladys") = %q, %v, want match for %#q, nil`, msg, err, want)
    }
}

// TestHelloEmpty 调用 greetings.Hello 函数,并检查是否返回错误。
func TestHelloEmpty(t *testing.T) {
    msg, err := Hello("")
    if msg != "" || err == nil {
        t.Fatalf(`Hello("") = %q, %v, want "", error`, msg, err)
    }
}

此时还缺少go.mod文件

  1. 打开终端或命令提示符。
  2. 使用cd命令导航到项目目录C:\GoLandProjects\greetings
cd C:\GoLandProjectsfile\greetings

运行以下命令来初始化一个新的Go模块:

go mod init greetings

greetings目录下的命令行中运行go test命令来执行测试。go test命令会执行以Test开头的测试函数,以及在文件名以_test.go结尾的测试文件。

PASS ok greetings 1.295s 3. 希望得到更详细的输出,可以添加-v标志来获取所有测试及其结果的列表。

go test -v

=== RUN TestHelloName --- PASS: TestHelloName (0.00s) === RUN TestHelloEmpty --- PASS: TestHelloEmpty (0.00s) PASS ok greetings 0.621s

ep6.3尝试使用 -bench 参数,对编写的函数进行性能测试(续ep6.2)

阅读资料testing package - testing - Go Packages

在测试文件greetings_test.go中添加一个性能测试函数。示例代码如下:

// BenchmarkHello benchmarks the performance of the Hello function.
func BenchmarkHello(b *testing.B) {
    // Run the Hello function b.N times.
    for i := 0; i < b.N; i   {
        Hello("Gladys")
    }
}

在上面的示例中,我们编写了一个性能测试函数BenchmarkHello。该函数使用testing.B类型的参数,这是用于性能测试的辅助对象。在测试函数中,我们运行Hello函数b.N次,其中b.N是由测试框架决定的运行次数,以便在足够长的时间内得到可靠的测试结果。

现在,在项目目录中运行性能测试命令:

go test -bench=.

运行以上命令时,Go测试框架会执行BenchmarkHello函数并测量其性能。

请注意,性能测试的结果可能会因为不同的硬件配置、运行环境和代码优化而有所不同。因此,在进行性能测试时,最好在相同的硬件环境下多次运行测试,并观察结果的趋势。

可以选择的 -bench 参数语法如下:

  • -bench=.:运行所有的基准测试函数。

ok greetings 1.952s

  • -bench=Pattern.:运行所有与正则表达式 Pattern 匹配的基准测试函数。

BenchmarkHello-20 16258156 74.45 ns/op PASS ok greetings 1.952s

ep6.4性能优化指南

  1. 使用性能分析:

    • 利用内置的性能分析工具如 pprof 来识别代码中的性能瓶颈。
    • 运行 go tool pprof 来分析CPU和内存的使用情况。
  2. 进行基准测试:

    • 使用 testing 包编写基准测试来测量代码中关键部分的性能。
    • 使用 go test -bench 命令来运行基准测试。
  3. 减少垃圾回收(GC)压力:

    • 减少不必要的对象创建,从而降低垃圾回收的频率和持续时间。
    • 使用对象池和 sync.Pool 来复用对象。
  4. 谨慎分配内存:

    • 避免在热代码段中进行不必要的内存分配。
    • 在可能的情况下,优先使用栈分配而不是堆分配。
    • 对于已知大小的数组或切片,进行预分配。
  5. 使用内置的并发特性:

    • 利用 goroutines 和 channels 来实现并发编程。
    • 在访问共享数据时要注意数据竞争,并使用互斥锁或原子操作来进行同步。
  6. 利用 sync/atomic 包:

    • 处理共享变量并避免竞态条件时,使用 sync/atomic 包来替代锁。
    • 原子操作在性能上更高效,但在使用时要注意一些限制。
  7. 减少内存拷贝:

    • 尽量减少不必要的数据拷贝,可以使用指针传递或者使用切片引用原始数据。
    • 使用 io.Readerio.Writer 接口进行高效的数据传输。
  8. 优化缓存局部性:

    • 组织数据结构以最大化缓存局部性,从而减少缓存未命中的次数。
    • 在处理 goroutines 之间的共享数据时要注意虚假共享。
  9. 选择合适的数据结构:

    • 根据具体的使用场景选择合适的数据结构。例如,使用 map 来进行快速的键值访问,使用切片来处理变长序列,使用数组来处理固定长度集合。
  10. 编译器优化标志:

  • 使用编译器的优化标志如 -O 或者 -gcflags 来指示编译器进行代码优化。
  • 注意过于激进的优化可能会导致较长的编译时间。
  1. 避免过度的字符串拼接:
  • 字符串拼接可能会创建多个中间字符串,增加内存使用和垃圾回收的压力。
  • 考虑使用 strings.Builder 或者 bytes.Buffer 来进行高效的字符串拼接。
  1. 使用合适的算法:
  • 选择适合具体任务的算法和数据结构,它们会对性能产生重要影响。

需要注意的是,过早进行优化往往事倍功半,因此在做出优化之前,应该先进行性能分析,重点放在编写清晰易读的代码上,然后根据需要识别和解决性能瓶颈。

ep7.1pprof(续ep6.1)

main.go 中加入 import _ "net/http/pprof" 后,运行程序时就会自动启动 PProf 的 HTTP 服务器,它会监听一个默认的端口(一般是 :6060),以便在浏览器中访问 http://localhost:6060/debug/pprof/ 来查看性能分析的数据。

import _ "net/http/pprof"

在terminal打开一个local

go build
./go-pprof-practice

接着在浏览器中访问 http://localhost:6060/debug/pprof/,将看到 PProf 的 Web UI。这里可以查看各种性能数据,如 CPU 和内存的使用情况,以及进行各种性能分析。 /debug/pprof/

Set debug=1 as a query parameter to export in legacy text format

Types of profiles available:

Count Profile
13 allocs
2 block
0 cmdline
47 goroutine
13 heap
1 mutex
0 profile
7 threadcreate
0 trace

full goroutine stack dump

Profile Descriptions:

  • allocs:

     A sampling of all past memory allocations

  • block:

     Stack traces that led to blocking on synchronization primitives

  • cmdline:

     The command line invocation of the current program

  • goroutine:

     Stack traces of all current goroutines. Use debug=2 as a query parameter to export in the same format as an unrecovered panic.

  • heap:

     A sampling of memory allocations of live objects. You can specify the gc GET parameter to run GC before taking the heap sample.

  • mutex:

     Stack traces of holders of contended mutexes

  • profile:

     CPU profile. You can specify the duration in the seconds GET parameter. After you get the profile file, use the go tool pprof command to investigate the profile.

  • threadcreate:

     Stack traces that led to the creation of new OS threads

  • trace:

     A trace of execution of the current program. You can specify the duration in the seconds GET parameter. After you get the trace file, use the go tool trace command to investigate the trace.

需要在terminal中打开两个local 在保证一个local程序是运行的情况下(ps:ctrl c停止运行)在另一个local中输入

go tool pprof -seconds=10 http://localhost:6060/debug/pprof/profile

在十秒钟内收集性能数据,在命令行中呈现。

Type: cpu

Time: Aug 2, 2023 at 11:43am (CST)

Duration: 10.12s, Total samples = 2.35s (23.22%)

(pprof) 输入top

Showing nodes accounting for 2.30s, 97.87% of 2.35s total

Dropped 39 nodes (cum <= 0.01s)

Showing top 10 nodes out of 11

flat flat% sum% cum cum%

2.25s 95.74% 95.74% 2.28s 97.02% github.com/wolfogre/go-pprof-

practice/animal/felidae/tiger.(*Tiger).Eat

0.03s 1.28% 97.02% 0.03s 1.28% runtime.asyncPreempt

0.01s 0.43% 97.45% 0.02s 0.85% fmt.(*pp).doPrintln

0.01s 0.43% 97.87% 0.02s 0.85% runtime.blockevent

0 0% 97.87% 0.03s 1.28% fmt.Sprintln

0 0% 97.87% 0.03s 1.28% github.com/wolfogre/go-pprof-

practice/animal/felidae/cat.(*Cat).Live

0 0% 97.87% 2.28s 97.02% github.com/wolfogre/go-pprof-

practice/animal/felidae/tiger.(*Tiger).Live

0 0% 97.87% 0.03s 1.28% log.Println

0 0% 97.87% 2.32s 98.72% main.main

0 0% 97.87% 2.32s 98.72% runtime.main

go tool pprof 输出中,以下是 flatflat%sum%cumcum% 的含义:

  1. flat: 表示函数在执行过程中所占用的总时间。它指的是函数本身的执行时间,并不包括它调用其他函数的时间。单位通常是纳秒(ns)或微秒(μs)。

  2. flat%: 表示函数在执行过程中所占用的总时间在整个执行时间中的百分比。这个百分比是相对于整个程序的执行时间来计算的。例如,如果某个函数的 flat% 是 10%,则表示该函数的执行时间占整个程序执行时间的 10%。

  3. sum%: 表示当前函数以及它调用的所有子函数的总时间在整个执行时间中的百分比。这包括了函数本身执行的时间以及它调用的所有子函数的执行时间。对于递归函数,可能会导致 sum% 大于 100%。

  4. cum: 表示从程序开始执行到当前函数执行完成的时间。它包括当前函数的执行时间以及它之前所有函数的执行时间,因此是一个累积时间。

  5. cum%: 表示从程序开始执行到当前函数执行完成的时间在整个执行时间中的百分比。这个百分比是相对于整个程序的执行时间来计算的。例如,如果某个函数的 cum% 是 20%,则表示从程序开始执行到该函数执行完成的时间占整个程序执行时间的 20%。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgbcgbg
系列文章
更多 icon
同类精品
更多 icon
继续加载