本文共 4406 字,大约阅读时间需要 14 分钟。
Go语言基础(十二)
一、pprof调试工具
二、获取命令行参数
三、面试题分享
Go语言性能优化主要有以下几个方面:
在计算机性能调试领域里,profiling是指对应用程序的画像,画像就是应用程序使用CPU和内存的情况,Go语言中自带profiling库。Go语言中内置了获取程序的运行数据的工具,包括以下两个标准库:
pprof开启后,每个一段时间(ms)就会收集下当前的堆栈信息,获取各个函数占用的CPU以及内存资源,最后通过对这些采样数据进行分析,形成一个性能报告。
1、CPU性能分析
开启CPU性能分析:
pprof.StartCPUProfile(w io.Writer)
停止CPU性能分析:
pprof.StopCPUProfile()
应用执行结束后,就会产生一个新文件,保存CPU Profiling数据,得到采样数据之后,使用go tool pprof工具进行CPU性能分析。
2、内存性能优化
记录程序的堆栈信息:
pprof.WriteHeapProfile(w io.Writer)
得到采样数据之后,使用go tool pprof工具进行内存性能分析,go tool pprof默认使用
-inuse_space进行统计,还可以使用-inuse-objects查看分配对象的数量。
3、服务型应用
使用net/pprof库,它能够提供HTTP服务进行分析。如果使用默认的http.DefaultServeMux通常代码直接使用http.ListenAndServe("0.0.0.0:8000", nil),只需要:
import _ "net/http/pprof"
如果使用自定义的Mux,则需要手动注册一些路由规则。
如果使用的是gin框架,推荐使用“github.con/DeanThompson/ginpprof”
4、具体示例
package mainimport ( "flag" "fmt" "os" "runtime/pprof" "time")// 一段有问题的代码func logicCode() { var c chan int // nil for { select { case v := <-c: // 阻塞 fmt.Printf("recv from chan, value:%vn", v) default: } }}func main() { var isCPUPprof bool var isMemPprof bool flag.BoolVar(&isCPUPprof, "cpu", false, "trun cpu pprof on") flag.BoolVar(&isMemPprof, "mem", false, "turn men pprof on") flag.Parse() if isCPUPprof { f1, err := os.Create("./cpu.pprof") if err != nil { fmt.Printf("create cpu pprof failed, err:%vn", err) return } pprof.StartCPUProfile(f1) defer func() { pprof.StopCPUProfile() f1.Close() }() } for i := 0; i < 6; i++ { go logicCode() } time.Sleep(10 * time.Second) if isMemPprof { f2, err := os.Create("./mem.pprof") if err != nil { fmt.Printf("create mem pprof failed, err:%vn", err) return } pprof.WriteHeapProfile(f2) f2.Close() }}
执行xxx.exe -cpu=true之后生成一个cpu.pprof,使用go tool pprof cpu.pprof进入交互界面:
在交互界面输入top3或者top5查看程序中占用CPU前3位或前5位的函数:
其中:
使用list 函数名命令查看具体的函数分析,例如:
将有问题的代码进行修复:
func logicCode() { var c chan int // nil for { select { case v := <-c: // 阻塞 fmt.Printf("recv from chan, value:%vn", v) default: time.Sleep(time.Millisecond * 500) } }}
再次执行:
5、图形化
windows下载[graphviz](https://graphviz.gitlab.io/_pages/Download/Download_windows.html)将graphviz安装目录下的bin文件添加到Path环境变量中,在终端输入dot -version查看是否安装成功。
在交互界面输入web,会在本地浏览器打开一张svg的图片:
6、go-torch火焰图
后续更新
1、os.Arg获取命令行参数
package mainimport ( "fmt" "os")// os.Arg获取命令行参数func main() { fmt.Printf("%#vn", os.Args) fmt.Println(os.Args[0], os.Args[2]) fmt.Printf("%Tn", os.Args)}
2、定义命令行flag参数
flag包支持的命令行参数类型有bool、int、int64、uint、uint64、float、float64、string、duration。
package mainimport ( "flag" "fmt" "time")// flag 获取命令行参数func main() { // 创建一个标志位参数 name := flag.String("name", "康辉", "请输入名字") age := flag.Int("age", 25, "请输入真是年龄") married := flag.Bool("married", false, "结婚了吗") cTime := flag.Duration("ct", time.Second, "结婚多久了?") flag.Parse() fmt.Println(*name) fmt.Println(*age) fmt.Println(*married) fmt.Println(*cTime) fmt.Println(flag.Args()) fmt.Println(flag.NArg()) fmt.Println(flag.NFlag())}
package mainimport ( "flag" "fmt" "time")func main() { var name string var age int var married bool var delay time.Duration flag.StringVar(&name, "name", "张三", "姓名") flag.IntVar(&age, "age", 18, "年龄") flag.BoolVar(&married, "married", false, "婚否") flag.DurationVar(&delay, "d", 0, "时间间隔") flag.Parse() fmt.Println(name) fmt.Println(age) fmt.Println(married) fmt.Println(delay)}
3、flag.Parse()
通过以上两种方法定义好命令行flag参数后,使用flag.Parse()来对命令进行解析。
支持的命令行参数格式有以下几种:
其中,布尔类型的参数必须使用等号的方式指定。
flag其他函数:
flag.Args() // 返回命令行参数后的其他参数,以[]string类型flag.NArg() // 返回命令行参数后的其他参数个数flag.Nflag() // 返回使用的命令行参数个数
1、爬台阶
func f(n int) int { if n == 1{ retrun 1 } if n == 2 { retrun 2 } retrun f(n-1) + f(n-2)}
虽然这样递归能够解决问题,但是如果有1w或者更多的台阶,显然这不是一个最优解法。
最优解法:待更新。
2、判断一个链表是否闭环?
每日一句毒鸡汤:某些希望的破灭其实也是好事,最起码不用每天带着傻傻的期望,能够犀利死心地去投入到新的开始。
本次推荐:
题库 - 力扣 (LeetCode)leetcode-cn.com继续加油~!
立个flag,坚持刷LeetCode并附上python和Go的代码!
转载地址:http://yljdv.baihongyu.com/