成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go 高性能 - 打印調用堆棧

開發 前端
本小節介紹了兩種獲取堆棧信息的方法,并通過基準測試來分析兩種方法的性能差異,讀者可以在此基礎上封裝自己的高性能組件類庫。

概述

在工程代碼中需要在異常場景打印相應的日志,記錄重要的上下文信息。如果遇到 panic 或 error 的情況, 這時候就需要詳細的 堆棧信息 作為輔助來排查問題,本小節就來介紹兩種常見的獲取 堆棧信息 方法, 然后對兩種方法進行基準測試,最后使用測試的結果進行性能對比并分析差異。

runtime.Stack

通過標準庫提供的 runtime.Stack 相關 API 來獲取。

示例

package main

import (
"fmt"
"runtime"
)

func main() {
buf := make([]byte, 1024)
n := runtime.Stack(buf, true)

fmt.Printf("%s\n", buf[:n])
}
$ go run main.go

# 輸出如下 (你的輸出代碼路徑應該和這里的不一樣)
goroutine 1 [running]:
main.main()
/home/codes/go-high-performance/main.go:10 +0x45
...

測試代碼如下

package performance

import (
"runtime"
"testing"
)

func Benchmark_StackDump(b *testing.B) {
for i := 0; i < b.N; i++ {
buf := make([]byte, 1024)
n := runtime.Stack(buf, true)

_ = buf[:n]
}
}

運行測試,并將基準測試結果寫入文件:

# 運行 1000 次,統計內存分配
$ go test -run='^$' -bench=. -count=1 -benchtime=1000x -benchmem > slow.txt

runtime.Caller

通過標準庫提供的 runtime.Caller 相關 API 來獲取。

示例

package main

import (
"fmt"
"runtime"
)

func main() {
for i := 0; ; i++ {
if _, file, line, ok := runtime.Caller(i); ok {
fmt.Printf("file: %s, line: %d\n", file, line)
} else {
break
}
}
}
$ go run main.go

# 輸出如下 (你的輸出代碼路徑應該和這里的不一樣)
file: /home/codes/go-high-performance/main.go, line: 10
file: /usr/local/go/src/runtime/proc.go, line: 250
file: /usr/local/go/src/runtime/asm_amd64.s, line: 1594
...

從輸出的結果中可以看到,runtime.Caller 的返回值包含了 文件名稱 和 行號,但是相比 runtime.Stack 的輸出而言, 缺少了 goroutine 和 調用方法 字段,我們可以通過 runtime.Callers 配合 runtime.CallersFrames 輸出和 runtime.Stack 一樣的結果。

package main

import (
"fmt"
"runtime"
"strconv"
"strings"
)

func main() {
pcs := make([]uintptr, 16)
n := runtime.Callers(0, pcs)

frames := runtime.CallersFrames(pcs[:n])

var sb strings.Builder
for {
frame, more := frames.Next()

sb.WriteString(frame.Function)
sb.WriteByte('\n')
sb.WriteByte('\t')
sb.WriteString(frame.File)
sb.WriteByte(':')
sb.WriteString(strconv.Itoa(frame.Line))
sb.WriteByte('\n')

if !more {
break
}
}

fmt.Println(sb.String())
}
$ go run main.go

# 輸出如下 (你的輸出代碼路徑應該和這里的不一樣)
runtime.Callers
/usr/local/go/src/runtime/extern.go:247
main.main
/home/codes/go-high-performance/main.go:12
runtime.main
/usr/local/go/src/runtime/proc.go:250
runtime.goexit
/usr/local/go/src/runtime/asm_amd64.s:1594
...

測試代碼

package performance

import (
"runtime"
"strconv"
"strings"
"testing"
)

func stackDump() string {
pcs := make([]uintptr, 16)
n := runtime.Callers(0, pcs)

frames := runtime.CallersFrames(pcs[:n])

var buffer strings.Builder
for {
frame, more := frames.Next()

buffer.WriteString(frame.Function)
buffer.WriteByte('\n')
buffer.WriteByte('\t')
buffer.WriteString(frame.File)
buffer.WriteByte(':')
buffer.WriteString(strconv.Itoa(frame.Line))
buffer.WriteByte('\n')

if !more {
break
}
}

return buffer.String()
}

func Benchmark_StackDump(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = stackDump()
}
}

運行測試,并將基準測試結果寫入文件:

# 運行 1000 次,統計內存分配
$ go test -run='^$' -bench=. -count=1 -benchtime=1000x -benchmem > fast.txt

使用 benchstat 比較差異

$ benchstat -alpha=100 fast.txt slow.txt 

# 輸出如下
name old time/op new time/op delta
_StackDump-8 2.28μs ± 0% 68.89μs ± 0% +2926.85% (p=1.000 n=1+1)

name old alloc/op new alloc/op delta
_StackDump-8 1.36kB ± 0% 1.02kB ± 0% -24.71% (p=1.000 n=1+1)

name old allocs/op new allocs/op delta
_StackDump-8 12.0 ± 0% 1.0 ± 0% -91.67% (p=1.000 n=1+1)

輸出的結果分為了三行,分別對應基準測試期間的: 運行時間、內存分配總量、內存分配次數,可以看到:

  • ? 運行時間: runtime.Callers 比 runtime.Stack 提升了將近 30 倍
  • ? 內存分配總量: 兩者差不多
  • ? 內存分配次數: runtime.Callers 比 runtime.Stack 降低了將近 10 倍,當然筆者的測試代碼也需要再優化下

性能分析

最根本的差異點在于 runtime.Stack 會觸發 STW 操作。

小結

本小節介紹了兩種獲取堆棧信息的方法,并通過基準測試來分析兩種方法的性能差異,讀者可以在此基礎上封裝自己的高性能組件類庫。


責任編輯:武曉燕 來源: 真沒什么深度
相關推薦

2022-03-21 14:13:22

Go語言編程

2024-12-25 14:03:03

2021-08-13 09:06:52

Go高性能優化

2021-05-27 10:02:57

Go緩存數據

2025-01-13 13:00:00

Go網絡框架nbio

2025-02-05 12:09:12

2024-04-28 10:17:30

gnetGo語言

2023-12-26 00:58:53

Web應用Go語言

2023-12-01 07:06:14

Go命令行性能

2023-12-14 08:01:08

事件管理器Go

2023-11-01 10:58:31

系統調用高性能網絡編程Linux

2023-05-18 08:47:42

2019-03-01 11:03:22

Lustre高性能計算

2024-07-30 09:02:15

2025-05-06 01:00:00

Excel高性能內存

2020-07-16 08:06:53

網關高性能

2017-07-07 16:36:28

BIOIO模型 NIO

2017-11-28 17:14:16

華為云

2020-01-07 16:16:57

Kafka開源消息系統

2024-04-25 10:09:02

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一级做a爰片性色毛片16 | 日韩精品一区二区三区中文在线 | 一区二区三区四区免费观看 | 亚洲一区在线日韩在线深爱 | 97超碰人人| 做a视频在线观看 | 密桃av| 日韩欧美在线播放 | www.亚洲| 国产精品二区三区在线观看 | 99精品国产一区二区青青牛奶 | 99久久精品国产麻豆演员表 | 欧美二区在线 | 美女国产 | 羞羞视频网站免费观看 | 日韩国产中文字幕 | 日本不卡一区二区三区在线观看 | 日韩伦理电影免费在线观看 | 国产精品欧美精品日韩精品 | 欧美在线视频一区二区 | 久久久国产一区 | 亚洲 成人 av| 精久久| 91精品国产一区二区三区香蕉 | 亚洲韩国精品 | 一区二区小视频 | 午夜精品久久久久久久久久久久久 | 国产日韩一区 | 成年人在线视频 | 亚洲一区二区三区视频免费观看 | 亚洲国产午夜 | 99视频在线免费观看 | 一级看片免费视频 | 午夜影院 | 国产乱码高清区二区三区在线 | 福利影院在线看 | www.一区二区 | 欧美炮房| 在线一区观看 | 国产精品精品视频一区二区三区 | 国产三级|