写点什么

Go 语言开发小技巧 & 易错点 100 例(五)

作者:海风极客
  • 2023-04-15
    北京
  • 本文字数:1670 字

    阅读完需:约 5 分钟

往期回顾:



本期看点(技巧类用【技】表示,易错点用【易】表示)


(1)pprof 查看运行时状态信息【技】


(2)goruntine 使用后的销毁【易】


PS:《Go语言开发小技巧&易错点100例》算上这一篇已经完成了20篇啦!五分之一!继续加油


正文如下:

1 pprof 查看运行时状态信息

pprof 是 Go 语言的性能分析工具,主要可以分析以下几种情况:


  • allocs:过去所有内存分配的示例

  • block:导致同步原语阻塞的堆栈跟踪

  • cmdline:当前程序的命令行调用

  • goroutine:当前所有 goroutine 的堆栈跟踪

  • heap:活动对象的内存分配示例。您可以指定 gc GET 参数,以便在执行堆样例之前运行 gc。

  • mutex:竞争互斥对象持有者的堆栈跟踪

  • profile:CPU profile。可以在 seconds GET 参数中指定持续时间。获得概要文件后,使用 go 工具 pprof 命令来研究概要文件。

  • threadcreate:用于创建新的操作系统线程的堆栈跟踪

  • trace:当前程序执行的跟踪。可以在 seconds GET 参数中指定持续时间。获得跟踪文件后,使用 go 工具 trace 命令来调查跟踪。


运行代码:


package main
import ( "fmt" "net/http" _ "net/http/pprof" "strings")
func main() { http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { writer.Write([]byte("Hello~")) }) http.ListenAndServe(":9090", nil) }
复制代码


访问链接:http://localhost:9090/debug/pprof/


2 goruntine 使用后的销毁

在上节我们学到了如何去控制 goruntine 的数量,因为短时间内大量的 goroutine 同时执行也会造成内存崩溃、CPU 占用率过高等问题,不仅如此,当 goruntine 启动后未进行关闭时,因为大量的挤压 goroutine 也会造成相同的问题,因此我们要习惯在项目中使用 goruntine 后进行关闭。

2.1 使用后不销毁出现的问题示例

代码示例:


package main
import ( "fmt" "net/http" _ "net/http/pprof")
func main() { ints := make(chan int,1000) i := 0
worker := func (ch chan int){ for v := range ch { fmt.Println(v) } }
http.HandleFunc("/go", func(writer http.ResponseWriter, request *http.Request) { i+=1 ints<-i go worker(ints) }) http.ListenAndServe(":9090", nil)}
复制代码


查看 pprof:



我们发现同一个地方我们只 go 出去一次,但是几次请求后还是有很多 goruntine,这样如果大批量请求的话一定会出问题。

2.2 使用后销毁的方式

2.2.1 优化代码逻辑

第一种优化方式,就是换一种方式去监听 channel:


package main
import ( "fmt" "net/http" _ "net/http/pprof")

func main() { ints := make(chan int,1000) i := 0
worker := func (ch chan int){ select { case v := <-ch: fmt.Println(v) default: return } }
http.HandleFunc("/go", func(writer http.ResponseWriter, request *http.Request) { i+=1 ints<-i go worker(ints) }) http.ListenAndServe(":9090", nil)}
复制代码
2.2.2 利用 channel 销毁多余的 goruntine

第二种方式,我们可以 close 掉 channel 来间接的关闭监听他的 goruntine


package main
import ( "fmt" "net/http" _ "net/http/pprof")
func worker(v ...int) { count := len(v) res :=make(chan int,count)
go func (ch chan int){ for i := 0; i < count; i++ { fmt.Println(v[i]) ch <- v[i] } }(res)
for i := 0; i < count; i++ { <-res }
close(res)}
func main() { val := 0
http.HandleFunc("/go", func(writer http.ResponseWriter, request *http.Request) { val += 1 go worker(val) }) http.ListenAndServe(":9090", nil)}
复制代码
2.2.3 利用 Context 销毁多余的 goruntine

第三种方式,使用 Context 机制关闭多余的 goruntine

发布于: 刚刚阅读数: 3
用户头像

海风极客

关注

做兴趣使然的Hero 2021-01-14 加入

Just do it.

评论

发布
暂无评论
Go语言开发小技巧&易错点100例(五)_三周年连更_海风极客_InfoQ写作社区