「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。
在前一篇文章中,go逃逸分析通过使用一个在goroutine的堆栈上共享一个值的例子讲解逃逸分析的基础知识。为了更清晰的讲解逃逸分析的情况,这篇文章调试一个简单的程序,查看编译器如何分配值。
情景
给定一个字节流,编写一个函数来查找字符串elvis并将其替换为字符串Elvis
这篇文章将重点关注algOne函数,使用io包编写algOne函数。 可以使用algTwo函数测试内存和cpu概要(cpu profile)文件。使用的输入数据和algOne函数将要产生的预期输出如下。
输入: abcelvisaElvisabcelviseelvisaelvisaabeeeelvise l v i saa bb e l v i saa elvi selvielviselvielvielviselvi1elvielviselvis
输出: abcElvisaElvisabcElviseElvisaElvisaabeeeElvise l v i saa bb e l v i saa elvi selviElviselvielviElviselvi1elviElvisElvis
func algOne(data []byte, find []byte, repl []byte, output *bytes.Buffer) {
input := bytes.NewBuffer(data)
size := len(find)
buf := make([]byte, size)
end := size - 1
if n, err := io.ReadFull(input, buf[:end]); err != nil {
output.Write(buf[:n])
return
}
for {
if _, err := io.ReadFull(input, buf[:end]); err != nil {
output.Write(buf[:end])
return
}
if bytes.Compare(buf, find) == 0 {
output.Write(repl)
if n, err := io.ReadFull(input, buf[:end]); err != nil {
output.Write(buf[:n])
return
}
continue
}
output.WriteByte(buf[0])
copy(buf, buf[1:])
}
}
- data:数据流
- find:需要替换的字符串
- repl:替换的字符串
- io.ReadFull:该函数从第一个参数input中读取第二个参数buf长度的数据,并写入buf中
基准测试(Benchmark)
想知道的是这个函数的性能如何,以及它对堆的压力有多大。 为了了解这一点,我们将运行一个基准测试。有了这个基准测试函数,我们就可以使用-bench、-benchtime和-benchmem开关对它进行测试。在运行基准测试之后,我们可以看到algOne函数正在为每个操作分配两个值,为117字节。
func BenchmarkAlgorighmOne(b *testing.B) {
var output bytes.Buffer
in := []byte("abcelvisaElvisabcelviseelvisaelvisaabeeeelvise l v i saa bb e l v i saa elviselvielviselvielvielviselvi1elvielviselvis")
find := []byte("elvis")
repl := []byte("Elvis")
b.ResetTimer()
for i := 0; i < b.N; i++ {
output.Reset()
algOne(in, find, repl, &output)
}
}
go test -run none -bench AlgorithmOne -benchtime 3s -benchmem
BenchmarkAlgorithmOne-8 2000000 2522 ns/op 117 B/op 2 allocs/op
分析数据生成(Profile)
我们需要知道函数中的哪些代码行导致了这些分配。 要了解这一点,我们需要为这个基准生成分析数据。
go test -run none -bench AlgorithmOne -benchtime 3s -benchmem -memprofile mem.out
BenchmarkAlgorithmOne-8 2000000 2570 ns/op 117 B/op 2 allocs/op
一旦基准测试完成,测试工具就会生成两个新文件。源代码在一个名为memcpu的文件夹中, 生成的两个新文件为mem.out,mem.cpu.test。 输出文件包含profile文件和memcpu.test测试文件,profile文件和测试二进制文件就绪后,可以采用go工具进行性能分析。下一篇文章讲解如何使用go的pprof工具进行性能分析。
总结
使用io包构建了字符串查找,替换函数,并为其编写了基准测试,生成profile数据。本文参考并翻译了参考文献第一篇。