一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

使用Delve進(jìn)行Golang代碼的調(diào)試

 KyunraWang 2018-05-10
https://yq.aliyun.com/articles/57578

追蹤代碼中的錯誤可能是一件非常頭疼的事情。這在高度依賴goroutine的Golang代碼調(diào)試中更加的突出。有一個趁手的 debug 工具就顯得非常的重要。我們先來看看 Go 官方的debug tool文檔寫的啥。

GDB does not understand Go programs well. The stack management, threading, and runtime contain aspects that differ enough from the execution model GDB expects that they can confuse the debugger, even when the program is compiled with gccgo.

In short, the instructions below should be taken only as a guide to how to use GDB when it works, not as a guarantee of success.

In time, a more Go-centric debugging architecture may be required.

總結(jié)一下上面說的話。

  1. Go 的debug工具有GDB這個玩意,但是目前貌似工作的不咋滴
  2. 目前官方只是給你介紹介紹這個玩意怎么用,但是不保證能成功
  3. 實話說,我們需要一個更懂 Go 的調(diào)試器

最后一句話透露了本質(zhì),目前還沒有一個非常好的調(diào)試工具。難道我們只能在不斷打日志然后 build 然后再打日志中調(diào)試程序嗎? 當(dāng)然不是,下面我來介紹一個專門為 Go而生的 debug 工具 Delve

Delve目的就是為了解決開發(fā)者在使用 GDB 調(diào)試中遇到的各種各樣的問題。我們開始詳細(xì)的介紹一些使用Delve 調(diào)試代碼的例子。

安裝

首先默認(rèn)你已經(jīng)安裝了 Go 環(huán)境,安裝命令很簡單,一句話。

go get github.com/derekparker/delve/cmd/dlv

注意:如果你使用Go1.5,你必須在運行這個命令前設(shè)置GO15VENDOREXPERIMENT=1

調(diào)試代碼

首先得說明一下,實誠點說,當(dāng)你想用debug 工具的時候,你的代碼估計已經(jīng)不按照你想象的方式運行了。只是你不知道為什么會這樣,因此你可能需要換一種方式啟動你的程序,下面我們來演示一下如果使用dlv來啟動你的程序。我們的示例代碼如下:

package main

import (
    "fmt"
    "sync"
    "time"
)

func dostuff(wg *sync.WaitGroup, i int) {
    fmt.Printf("goroutine id %d\n", i)
    time.Sleep(300 * time.Second)
    fmt.Printf("goroutine id %d\n", i)
    wg.Done()
}

func main() {
    var wg sync.WaitGroup
    workers := 10

    wg.Add(workers)
    for i := 0; i < workers; i++ {
        go dostuff(&wg, i)
    }
    wg.Wait()
}

在這個示例代碼中,我們創(chuàng)建了10個goroutine,這種代碼對于 GDB 來說是幾乎不可讀的,因為它對于goroutine的支持很差。但是Delve作為一個專業(yè)的 Go 調(diào)試器,對于goroutine這種殺手級功能還是非常了解的。下面我們來啟動程序。

dlv debug test-debug.go

運行這個命令,dlv會去編譯你的代碼,然后傳一些參數(shù)給編譯器,好讓編譯器編譯出來更加方便調(diào)試的可執(zhí)行文件,然后啟動了你的程序,并且attach上去,這樣你的console就會停留在了debug session,下面就可以調(diào)試程序了。

首先我們在main函數(shù)上設(shè)置一個斷點。

(dlv) break main.main
Breakpoint 1 set at 0x22d3 for main.main() ./test-debug.go:16

輸出信息里面告訴了我們斷點的 ID和斷點的位置,函數(shù)名和文件名以及所在行數(shù)。我們使用continue命令讓程序運行到我們打斷點的地方。

(dlv) continue
> main.main() ./test-debug.go:16 (hits goroutine(1):1 total:1) (PC: 0x22d3)
    11:        time.Sleep(300 * time.Second)
    12:        fmt.Printf("goroutine id %d\n", i)
    13:        wg.Done()
    14:    }
    15:
=>  16:    func main() {
    17:        var wg sync.WaitGroup
    18:        workers := 10
    19:
    20:        wg.Add(workers)
    21:        for i := 0; i < workers; i++ {
(dlv)

現(xiàn)在程序就停在了第一個斷點,現(xiàn)在我們可以使用next命令讓程序運行到下一句話,如果你想繼續(xù)向下,可以直接按回車(Delve會重復(fù)上一條命令如果你按下回車鍵)。

(dlv) next
> main.main() ./test-debug.go:17 (PC: 0x22d7)
    12:        fmt.Printf("goroutine id %d\n", i)
    13:        wg.Done()
    14:    }
    15:
    16:    func main() {
=>  17:        var wg sync.WaitGroup
    18:        workers := 10
    19:
    20:        wg.Add(workers)
    21:        for i := 0; i < workers; i++ {
    22:            go dostuff(&wg, i)
(dlv)
> main.main() ./test-debug.go:18 (PC: 0x22f1)
    13:        wg.Done()
    14:    }
    15:
    16:    func main() {
    17:        var wg sync.WaitGroup
=>  18:        workers := 10
    19:
    20:        wg.Add(workers)
    21:        for i := 0; i < workers; i++ {
    22:            go dostuff(&wg, i)
    23:        }
(dlv)
> main.main() ./test-debug.go:20 (PC: 0x22fa)
    15:
    16:    func main() {
    17:        var wg sync.WaitGroup
    18:        workers := 10
    19:
=>  20:        wg.Add(workers)
    21:        for i := 0; i < workers; i++ {
    22:            go dostuff(&wg, i)
    23:        }
    24:        wg.Wait()
    25:    }
(dlv)    

現(xiàn)在我們可以嘗試使用print命令去看一下變量的值。

(dlv) print wg
sync.WaitGroup {
    state1: [12]uint8 [0,0,0,0,0,0,0,0,0,0,0,0],
    sema: 0,}
(dlv) print workers
10
(dlv)

同時你也可以輸出一個表達(dá)式

(dlv) print workers < 100
true

下面我們在另外一個函數(shù)dostuff 上設(shè)置一個斷點

(dlv) break dostuff
Breakpoint 2 set at 0x2058 for main.dostuff() ./test-debug.go:9

我們使用continue到我們設(shè)置斷點的地方,然后next

(dlv) next
goroutine id 3
> main.dostuff() ./test-debug.go:10 (PC: 0x205f)
     5:        "sync"
     6:        "time"
     7:    )
     8:
     9:    func dostuff(wg *sync.WaitGroup, i int) {
=>  10:        fmt.Printf("goroutine id %d\n", i)
    11:        time.Sleep(300 * time.Second)
    12:        fmt.Printf("goroutine id %d\n", i)
    13:        wg.Done()
    14:    }
    15:
(dlv)

可以看到Delve會告訴你目前的goroutine id,我們試試輸出一下i和wg.

(dlv) print i
4
(dlv) print wg
*sync.WaitGroup {
    state1: [12]uint8 [1,0,0,0,10,0,0,0,0,0,0,0],
    sema: 0,}
    

我們創(chuàng)建了10個goroutine,如果你繼續(xù)使用next,你會發(fā)現(xiàn)你還是在同一個goroutine下。這樣就避免了被調(diào)試器跳轉(zhuǎn)到了另外的goroutine下導(dǎo)致不必要的調(diào)試錯誤??梢娺€是為 Go 而生的調(diào)試器才是真愛啊。

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

其實很多時候,我們調(diào)試的代碼可能是daemon程序或者需要實現(xiàn)編譯好在不同機(jī)器運行的程序。這就需要我們attach到一個已經(jīng)在運行中的程序上,下面我們就使用上面的代碼來演示一下如何attach到一個程序上進(jìn)行調(diào)試。首先將剛才的程序運行起來,我這里直接使用了

go build test-debug.go
./test-debug

然后使用ps查看正在運行的程序pid

  501 40994   549   0 12:08AM ttys003    0:00.00 ./test-debug
 

然后我們attach上去


dlv attach 40994

可以看到,熟悉的debug seesion又回來了。下面我們可以繼續(xù)使用上面的命令去設(shè)置斷點了

(dlv) break dostuff
Breakpoint 1 set at 0x2058 for main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:9
(dlv) break dostuff:3
Breakpoint 2 set at 0x2144 for main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12

我使用continue使程序運行到我設(shè)置斷點的地方

(dlv) continue
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(18):1 total:8) (PC: 0x2144)
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(19):1 total:8) (PC: 0x2144)
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(26):1 total:8) (PC: 0x2144)
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(23):1 total:8) (PC: 0x2144)
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(24):1 total:8) (PC: 0x2144)
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(20):1 total:8) (PC: 0x2144)
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(21):1 total:8) (PC: 0x2144)
> main.dostuff() /Users/xianlu/WorkSpace/golang/src/test-debug.go:12 (hits goroutine(25):1 total:8) (PC: 0x2144)
     7:    )
     8:
     9:    func dostuff(wg *sync.WaitGroup, i int) {
    10:        fmt.Printf("goroutine id %d\n", i)
    11:        time.Sleep(300 * time.Second)
=>  12:        fmt.Printf("goroutine id %d\n", i)
    13:        wg.Done()
    14:    }
    15:
    16:    func main() {
    17:        var wg sync.WaitGroup
(dlv)

可以看到,Delve已經(jīng)打印出來了當(dāng)前正在運行的goroutine,下面我們print一下我們當(dāng)前的i

(dlv) print i
7
(dlv) print wg
*sync.WaitGroup {
    state1: [12]uint8 [1,0,0,0,10,0,0,0,0,0,0,0],
    sema: 0,}

和上面一樣,而且attach到這個進(jìn)程后,也可以把對應(yīng)的源碼顯示出來,是不是很強(qiáng)大呢。更多的功能就自己參考文檔摸索吧。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    精品推荐国产麻豆剧传媒| 日韩中文高清在线专区| 国产成人在线一区二区三区| 亚洲精品日韩欧美精品| 国产日产欧美精品大秀| 日本熟妇熟女久久综合| 亚洲精品国产福利在线| 精品人妻精品一区二区三区| 国产精品制服丝袜美腿丝袜| 国产男女激情在线视频| 日韩人妻欧美一区二区久久| 日韩国产亚洲一区二区三区| 中文字幕亚洲精品乱码加勒比| 午夜精品福利视频观看| 国产偷拍盗摄一区二区| 少妇在线一区二区三区| 亚洲一区二区三区精选| 玩弄人妻少妇一区二区桃花| 欧美一区二区三区在线播放| 国产欧美日韩一级小黄片| 年轻女房东2中文字幕| 99久久国产综合精品二区| 久久精品色妇熟妇丰满人妻91 | 成人精品国产亚洲av久久| 午夜福利精品视频视频| 亚洲国产中文字幕在线观看| 日韩一级免费中文字幕视频| 暴力性生活在线免费视频| 又大又长又粗又黄国产| 亚洲欧美国产精品一区二区| 午夜精品一区免费视频| 国产又色又爽又黄又大| 成人免费视频免费观看| 欧美日韩一级aa大片| 亚洲一区二区三区福利视频| 国产在线成人免费高清观看av| 国产一级精品色特级色国产| 亚洲精品国产福利在线| 亚洲中文字幕在线综合视频| 五月的丁香婷婷综合网| 国产农村妇女成人精品|