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

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

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

[[412997]]

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

大家好,我是煎魚。

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

大家總嫌棄 pprof、trace 等工具,不夠細(xì),沒法一口氣看到根因,或者具體變量...希望能夠最好能追到代碼級(jí)別調(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。

演示程序

我們計(jì)劃用一個(gè)反轉(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 啟動(dòng)函數(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 程序的源代碼級(jí)調(diào)試器。Delve 使您能夠通過控制流程的執(zhí)行與您的程序進(jìn)行交互,查看變量,提供線程、goroutine、CPU 狀態(tài)等信息。

其一共支持如下 11 個(gè)子命令:

  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)前目錄下的主包,或指定的包,是最常用的功能之一。

接下來我們利用這個(gè)演示程序來進(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 的縮寫)對(duì) 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è)置完畢后,我們可以看到方法對(duì)應(yīng)的文件名、行數(shù)。接著我們可以執(zhí)行關(guān)鍵字 c(continue 的縮寫)跳轉(zhuǎn)到下一個(gè)斷點(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)行時(shí)信息。

緊接著執(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 方法去處理。

此時(shí)我們可以執(zhí)行關(guān)鍵字 s(step 的關(guān)鍵字)進(jìn)入到這個(gè)函數(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)會(huì)到 Reverse 方法上,此時(shí)我們可以調(diào)用關(guān)鍵字 p(print 的縮寫)傳出所傳入的變量的值:

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

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

但故事一般沒有這么的簡(jiǎn)單,會(huì)用到 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)來看,我們常常會(huì)懷疑是第 6 行可能是問題的所在。這時(shí)可以針對(duì)性的對(duì)第 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: } 

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

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

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

另外也可以調(diào)用關(guān)鍵字 set 去針對(duì)特定變量設(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í)行完畢后,整個(gè)調(diào)試就會(huì)重置,像是前面在打斷點(diǎn)時(shí)所設(shè)置的變量值就會(huì)恢復(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 對(duì)一些斷點(diǎn)清除:

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

若不指點(diǎn)斷點(diǎn),則會(huì)默認(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)行計(jì)算:

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

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

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

  1. (dlv) exit 

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

總結(jié)

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

 

像是假設(shè)程序的 for 循環(huán)運(yùn)行到第 N 次才出現(xiàn) BUG 時(shí),我們就可以通過斷點(diǎn)對(duì)應(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工具

2025-05-20 09:39:57

GogRPC微服務(wù)

2021-10-09 10:50:30

JavaScript編程開發(fā)

2021-05-30 07:56:51

QSettingsLog4Qt變量

2024-07-19 08:21:24

2024-12-19 00:16:43

2024-06-06 09:44:33

2024-06-03 08:09:39

2024-08-21 08:21:45

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

2024-08-02 10:28:13

算法NLP模型

2024-09-09 23:04:04

點(diǎn)贊
收藏

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

主站蜘蛛池模板: 在线观看视频h | 国内自拍偷拍一区 | 99热精品在线观看 | 免费亚洲婷婷 | 日韩欧美在线一区 | 久久影音先锋 | 成人免费影院 | 天天色天天 | 丝袜美腿一区二区三区动态图 | 欧美狠狠操 | 久久国产成人 | 日韩高清一区 | 亚洲成人中文字幕 | 国产欧美在线视频 | 99av成人精品国语自产拍 | 一区二视频 | www.国产一区| 成人免费在线播放视频 | m豆传媒在线链接观看 | 久久精品亚洲欧美日韩精品中文字幕 | 亚洲国产中文字幕 | 国产一区二区欧美 | 欧美寡妇偷汉性猛交 | 欧洲免费毛片 | 中文字幕在线视频一区二区三区 | 亚洲国产成人精品一区二区 | 一区二区三区四区免费视频 | 午夜成人免费视频 | 亚洲国产成人精品女人久久久 | www.se91 | 国产精品久久久久久久久久久久 | 欧洲av一区 | 视频在线一区 | www.久草.com| 国产激情片在线观看 | 一区二区免费 | 久久久久久亚洲国产精品 | 成人在线播放网站 | 国产精品久久久久久久久免费丝袜 | 99福利网| 欧美视频二区 |