自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一個 Demo 學(xué)會使用 Go Delve 調(diào)試

開發(fā) 后端
在 Go 語言中,Delve 調(diào)試工具是與 Go 語言親和度最高的,因?yàn)?Delve 是 Go 語言實(shí)現(xiàn)的。其在我們?nèi)粘9ぷ髦?,非常常用?/div>

[[412997]]

本文轉(zhuǎn)載自微信公眾號「腦子進(jìn)煎魚了」,作者陳煎魚。轉(zhuǎn)載本文請聯(lián)系腦子進(jìn)煎魚了公眾號。

大家好,我是煎魚。

在 Go 語言中,除了 go tool 工具鏈中的 pprof、trace 等剖析工具的大利器外。常常還會有小伙伴問,有沒有更好用,更精細(xì)的,

大家總嫌棄 pprof、trace 等工具,不夠細(xì),沒法一口氣看到根因,或者具體變量...希望能夠最好能追到代碼級別調(diào)試的,看到具體變量的值是怎么樣的,隨意想怎么看怎么看的那種。

為此今天給大家介紹 Go 語言強(qiáng)大的 Delve (dlv)調(diào)試工具,來更深入問題剖析。

安裝

我們需要先安裝 Go delve,若是 Go1.16 及以后的版本,可以直接執(zhí)行下述命令安裝:

  1. $ go install github.com/go-delve/delve/cmd/dlv@latest 

也可以通過 git clone 的方式安裝:

  1. $ git clone https://github.com/go-delve/delve 
  2. $ cd delve 
  3. $ go install github.com/go-delve/delve/cmd/dlv 

在安裝完畢后,我們執(zhí)行 dlv version 命令,查看安裝情況:

  1. $ dlv version 
  2. Delve Debugger 
  3. Version: 1.7.0 
  4. Build: $Id: e353a65161e6ed74952b96bbb62ebfc56090832b $ 

可以明確看到我們所安裝的版本是 v1.7.0。

演示程序

我們計劃用一個反轉(zhuǎn)字符串的演示程序來進(jìn)行 Go 程序的調(diào)試。第一部分先是完成 stringer 包的 Reverse 方法。

代碼如下:

  1. package stringer 
  2.  
  3. func Reverse(s string) string { 
  4.  r := []rune(s) 
  5.  for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { 
  6.   r[i], r[j] = r[j], r[i] 
  7.  } 
  8.  return string(r) 

再在具體的 main 啟動函數(shù)中進(jìn)行調(diào)用。代碼如下:

  1. import ( 
  2.  "fmt" 
  3.  
  4.  "github.com/eddycjy/awesome-project/stringer" 
  5.  
  6. func main() { 
  7.  fmt.Println(stringer.Reverse("腦子進(jìn)煎魚了!")) 

輸出結(jié)果:

  1. !了魚煎進(jìn)子腦 

進(jìn)行調(diào)試

Delve 是 Go 程序的源代碼級調(diào)試器。Delve 使您能夠通過控制流程的執(zhí)行與您的程序進(jìn)行交互,查看變量,提供線程、goroutine、CPU 狀態(tài)等信息。

其一共支持如下 11 個子命令:

  1. Available Commands: 
  2.   attach      Attach to running process and begin debugging. 
  3.   connect     Connect to a headless debug server. 
  4.   core        Examine a core dump. 
  5.   dap         [EXPERIMENTAL] Starts a TCP server communicating via Debug Adaptor Protocol (DAP). 
  6.   debug       Compile and begin debugging main package in current directory, or the package specified. 
  7.   exec        Execute a precompiled binaryand begin a debug session. 
  8.   help        Help about any command 
  9.   run         Deprecated command. Use 'debug' instead
  10.   test        Compile test binary and begin debugging program. 
  11.   trace       Compile and begin tracing program. 
  12.   version     Prints version. 

我們今天主要用到的是 debug 命令,他能夠編譯并開始調(diào)試當(dāng)前目錄下的主包,或指定的包,是最常用的功能之一。

接下來我們利用這個演示程序來進(jìn)行 dlv 的深入調(diào)試和應(yīng)用。

執(zhí)行如下命令:

  1. ➜  awesomeProject dlv debug . 
  2. Type 'help' for list of commands. 
  3. (dlv)  

我們先在演示程序根目錄下執(zhí)行了 debug,進(jìn)入了 dlv 的交互模式。

再使用關(guān)鍵字 b(break 的縮寫)對 main.main 方法設(shè)置斷點(diǎn):

  1. (dlv) b main.main 
  2. Breakpoint 1 (enabled) set at 0x10cbab3 for main.main() ./main.go:9 
  3. (dlv)  

設(shè)置完畢后,我們可以看到方法對應(yīng)的文件名、行數(shù)。接著我們可以執(zhí)行關(guān)鍵字 c(continue 的縮寫)跳轉(zhuǎn)到下一個斷點(diǎn)處:

  1. (dlv) c 
  2. > main.main() ./main.go:9 (hits goroutine(1):1 total:1) (PC: 0x10cbab3) 
  3.      4:  "fmt" 
  4.      5:  
  5.      6:  "github.com/eddycjy/awesome-project/stringer" 
  6.      7: ) 
  7.      8:  
  8. =>   9: func main() { 
  9.     10:  fmt.Println(stringer.Reverse("腦子進(jìn)煎魚了!")) 
  10.     11: } 
  11. (dlv)  

在斷點(diǎn)處,我看可以看到具體的代碼塊、goroutine、CPU 寄存器地址等運(yùn)行時信息。

緊接著執(zhí)行關(guān)鍵字 n(next 的縮寫)單步執(zhí)行程序的下一步:

  1. (dlv) n 
  2. > main.main() ./main.go:10 (PC: 0x10cbac1) 
  3.      5:  
  4.      6:  "github.com/eddycjy/awesome-project/stringer" 
  5.      7: ) 
  6.      8:  
  7.      9: func main() { 
  8. =>  10:  fmt.Println(stringer.Reverse("腦子進(jìn)煎魚了!")) 
  9.     11: } 

我們可以看到程序走到了 main.go 文件中的第 10 行中,并且調(diào)用了 stringer.Reverse 方法去處理。

此時我們可以執(zhí)行關(guān)鍵字 s(step 的關(guān)鍵字)進(jìn)入到這個函數(shù)中去繼續(xù)調(diào)試:

  1. (dlv) s 
  2. > github.com/eddycjy/awesome-project/stringer.Reverse() ./stringer/string.go:3 (PC: 0x10cb87b) 
  3.      1: package stringer 
  4.      2:  
  5. =>   3: func Reverse(s string) string { 
  6.      4:  r := []rune(s) 
  7.      5:  for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { 
  8.      6:   r[i], r[j] = r[j], r[i] 
  9.      7:  } 
  10.      8:  return string(r) 

輸入后,調(diào)試的光標(biāo)會到 Reverse 方法上,此時我們可以調(diào)用關(guān)鍵字 p(print 的縮寫)傳出所傳入的變量的值:

  1. (dlv) p s 
  2. "腦子進(jìn)煎魚了!" 

此處函數(shù)的形參變量是 s,輸出了 “腦子進(jìn)煎魚了!”,與我們所傳入的是一致的。

但故事一般沒有這么的簡單,會用到 Delve 來調(diào)試,說明是比較細(xì)致、隱患的 BUG。為此我們大多需要更進(jìn)一步的深入。

我們繼續(xù)圍觀 Reverse 方法:

  1. 5:  for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { 
  2.  6:   r[i], r[j] = r[j], r[i] 
  3.  7:  } 

從表現(xiàn)來看,我們常常會懷疑是第 6 行可能是問題的所在。這時可以針對性的對第 6 行進(jìn)行斷點(diǎn)查看:

  1. (dlv) b 6 
  2. Breakpoint 2 (enabled) set at 0x10cb92c for github.com/eddycjy/awesome-project/stringer.Reverse() ./stringer/string.go:6 

設(shè)置完斷點(diǎn)后,我們只需要執(zhí)行關(guān)鍵字 c,繼續(xù)下一步:

  1. (dlv) c 
  2. > github.com/eddycjy/awesome-project/stringer.Reverse() ./stringer/string.go:6 (hits goroutine(1):1 total:1) (PC: 0x10cb92c) 
  3.      1: package stringer 
  4.      2:  
  5.      3: func Reverse(s string) string { 
  6.      4:  r := []rune(s) 
  7.      5:  for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { 
  8. =>   6:   r[i], r[j] = r[j], r[i] 
  9.      7:  } 
  10.      8:  return string(r) 
  11.      9: } 

走到對應(yīng)的代碼片段后,執(zhí)行關(guān)鍵字 locals:

  1. (dlv) locals 
  2. r = []int32 len: 7, cap: 32, [...] 
  3. j = 6 
  4. i = 0 

我們就可以看到對應(yīng)的變量 r, i, j 的值是多少,可以根據(jù)此來分析程序流轉(zhuǎn)是否與我們預(yù)想的一致。

另外也可以調(diào)用關(guān)鍵字 set 去針對特定變量設(shè)置期望的值:

  1. (dlv) set i = 1 
  2. (dlv) locals 
  3. r = []int32 len: 7, cap: 32, [...] 
  4. j = 6 
  5. i = 1 

設(shè)置后,若還需要繼續(xù)排查,可以繼續(xù)調(diào)用關(guān)鍵字 c 去定位,這種常用于特定變量的特定值的異常,這樣一設(shè)置一調(diào)試基本就能排查出來了。

在排查完畢后,我們可以執(zhí)行關(guān)鍵字 r(reset 的縮寫):

  1. (dlv)  r 
  2. Process restarted with PID 56614 

執(zhí)行完畢后,整個調(diào)試就會重置,像是前面在打斷點(diǎn)時所設(shè)置的變量值就會恢復(fù)。

若要查看設(shè)置的斷點(diǎn)情況,也可以執(zhí)行關(guān)鍵字 bp 查看:

  1. (dlv) bp 
  2. Breakpoint runtime-fatal-throw (enabled) at 0x1038fc0 for runtime.fatalthrow() /usr/local/Cellar/go/1.16.2/libexec/src/runtime/panic.go:1163 (0) 
  3. Breakpoint unrecovered-panic (enabled) at 0x1039040 for runtime.fatalpanic() /usr/local/Cellar/go/1.16.2/libexec/src/runtime/panic.go:1190 (0) 
  4.  print runtime.curg._panic.arg 
  5. Breakpoint 1 (enabled) at 0x10cbab3 for main.main() ./main.go:9 (0) 
  6. Breakpoint 2 (enabled) at 0x10cb92c for github.com/eddycjy/awesome-project/stringer.Reverse() ./stringer/string.go:6 (0) 

查看斷點(diǎn)情況后,若有部分已經(jīng)排除了,可以調(diào)用關(guān)鍵字 clearall 對一些斷點(diǎn)清除:

  1. (dlv) clearall main.main 
  2. Breakpoint 1 (enabled) cleared at 0x10cbab3 for main.main() ./main.go:9 

若不指點(diǎn)斷點(diǎn),則會默認(rèn)清除全部斷點(diǎn)。

在日常的 Go 工程中,若都從 main 方法進(jìn)入就太繁瑣了。我們可以直接借助函數(shù)名進(jìn)行調(diào)式定位:

  1. (dlv) funcs Reverse 
  2. github.com/eddycjy/awesome-project/stringer.Reverse 
  3. (dlv) b stringer.Reverse 
  4. Breakpoint 3 (enabled) set at 0x10cb87b for github.com/eddycjy/awesome-project/stringer.Reverse() ./stringer/string.go:3 
  5. (dlv) c 
  6. > github.com/eddycjy/awesome-project/stringer.Reverse() ./stringer/string.go:3 (hits goroutine(1):1 total:1) (PC: 0x10cb87b) 
  7.      1: package stringer 
  8.      2:  
  9. =>   3: func Reverse(s string) string { 
  10.      4:  r := []rune(s) 
  11.      5:  for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { 
  12.      6:   r[i], r[j] = r[j], r[i] 
  13.      7:  } 
  14.      8:  return string(r) 

緊接著其他步驟都與先前的一樣,進(jìn)行具體的調(diào)試就好了。我們也可以借助 Go 語言的公共函數(shù)進(jìn)行計算:

  1. (dlv) p len(r)-1 

也可以借助關(guān)鍵字 vars 查看某個包下的所有全局變量的值,例如:vars main。這種方式對于查看全局變量的情況非常有幫助。

排查完畢后,執(zhí)行關(guān)鍵字 exit 就可以愉快的退出了:

  1. (dlv) exit 

解決完問題,可以下班了 :)

總結(jié)

在 Go 語言中,Delve 調(diào)試工具是與 Go 語言親和度最高的,因?yàn)?Delve 是 Go 語言實(shí)現(xiàn)的。其在我們?nèi)粘9ぷ髦?,非常常用?/p>

 

像是假設(shè)程序的 for 循環(huán)運(yùn)行到第 N 次才出現(xiàn) BUG 時,我們就可以通過斷點(diǎn)對應(yīng)的方法和代碼塊,再設(shè)置變量的值,進(jìn)行具體的查看,就可以解決。

 

責(zé)任編輯:武曉燕 來源: 腦子進(jìn)煎魚了
相關(guān)推薦

2021-07-28 08:53:53

GoGDB調(diào)試

2020-07-10 16:52:43

DelveGo程序開源

2021-07-29 07:55:19

Demo 工作池

2023-03-29 08:18:16

Go調(diào)試工具

2022-05-23 09:22:20

Go語言調(diào)試器Delve

2023-11-10 09:20:28

Java工具

2021-12-28 07:20:43

Hippo WebAssembly云原生

2023-12-27 07:40:43

HTTP服務(wù)器負(fù)載均衡

2021-07-26 05:07:23

Swift萬花尺代碼

2020-12-08 08:46:07

GoJava工具

2021-10-09 10:50:30

JavaScript編程開發(fā)

2021-05-30 07:56:51

QSettingsLog4Qt變量

2024-07-19 08:21:24

2024-06-06 09:44:33

2024-12-19 00:16:43

2024-06-03 08:09:39

2024-08-02 10:28:13

算法NLP模型

2024-08-21 08:21:45

CNN算法神經(jīng)網(wǎng)絡(luò)

2009-11-05 15:25:36

WCF服務(wù)端配置

2015-08-14 09:21:09

gdb工具調(diào)試 Go
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號