<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文詳解如何在調(diào)試過程中查找 Goroutine

          共 751字,需瀏覽 2分鐘

           ·

          2021-02-05 09:33

          點(diǎn)擊上方藍(lán)色“Go語言中文網(wǎng)”關(guān)注,每天一起學(xué) Go

          Goroutines 是大多數(shù)用 Go 編寫的程序的重要組成部分。但是,使用大量 goroutines 會(huì)使程序難以調(diào)試。那怎么辦?在此博文中,我們將介紹如何使用自定義數(shù)據(jù)為 goroutine 加上標(biāo)簽。

          目錄

          • 在 IDE 下使用
          • 在命令行下使用
          • 性能影響
          • 使用自定義庫啟用調(diào)試標(biāo)簽

          讓我們以向 Web 服務(wù)器發(fā)出請(qǐng)求的應(yīng)用程序?yàn)槔?/p>

          package?main
          ?
          import?(
          ????"io"
          ????"io/ioutil"
          ????"math/rand"
          ????"net/http"
          ????"strconv"
          ????"strings"
          ????"time"
          )
          ?
          func?fakeTraffic()?{
          ????//?Wait?for?the?server?to?start
          ????time.Sleep(1?*?time.Second)
          ?
          ????pages?:=?[]string{"/",?"/login",?"/logout",?"/products",?"/product/{productID}",?"/basket",?"/about"}
          ?
          ????activeConns?:=?make(chan?struct{},?10)
          ?
          ????c?:=?&http.Client{
          ????????Timeout:?10?*?time.Second,
          ????}
          ?
          ????i?:=?int64(0)
          ?
          ????for?{
          ????????activeConns?<-?struct{}{}
          ????????i++
          ?
          ????????page?:=?pages[rand.Intn(len(pages))]
          ?
          ????????//?We?need?to?launch?this?using?a?closure?function?to
          ????????//?ensure?that?we?capture?the?correct?value?for?the
          ????????//?two?parameters?we?need:?page?and?i
          ????????go?func(p?string,?rid?int64)?{
          ????????????makeRequest(activeConns,?c,?p,?rid)
          ????????}(page,?i)
          ????}
          }
          ?
          func?makeRequest(done?chan?struct{},?c?*http.Client,?page?string,?i?int64)?{
          ????defer?func()?{
          ????????//?Unblock?the?next?request?from?the?queue
          ????????<-done
          ????}()
          ?
          ????page?=?strings.Replace(page,?"{productID}",?"abc-"+strconv.Itoa(int(i)),?-1)
          ????r,?err?:=?http.NewRequest(http.MethodGet,?"http://localhost:8080"+page,?nil)
          ????if?err?!=?nil?{
          ????????return
          ????}
          ?
          ????resp,?err?:=?c.Do(r)
          ????if?err?!=?nil?{
          ????????return
          ????}
          ????defer?resp.Body.Close()
          ?
          ????_,?_?=?io.Copy(ioutil.Discard,?resp.Body)
          ?
          ????time.Sleep(time.Duration(10+rand.Intn(40))?+?time.Millisecond)
          }

          在 IDE 下使用

          如果我們?cè)谡{(diào)試器(debugger)中分析此代碼,我們?nèi)绾沃?makeRequest goroutines 在做什么?當(dāng)我們看這樣的清單時(shí),這些 goroutine 的執(zhí)行上下文什么?

          debugger without labels

          這就是 GoLand 新版本支持讀取 goroutines 標(biāo)簽的緣由。

          我們調(diào)整下上面的代碼:(polaris 注:pprof 是標(biāo)準(zhǔn)庫的 runtime/pprof )

          go?func(p?string,?rid?int64)?{
          ????labels?:=?pprof.Labels("request",?"automated",?"page",?p,?"rid",?strconv.Itoa(int(rid)))
          ????pprof.Do(context.Background(),?labels,?func(_?context.Context)?{
          ????????makeRequest(activeConns,?c,?p,?rid)
          ????})
          }(page,?i)

          現(xiàn)在,當(dāng)在調(diào)試器中運(yùn)行相同的代碼時(shí),我們將看到以下視圖:

          debugger with labels

          看起來好多了。現(xiàn)在,我們可以看到在標(biāo)簽中設(shè)置的所有信息。而且,最重要的是,我們還可以看到通過函數(shù)調(diào)用在后臺(tái)啟動(dòng)的其他 goroutine,它們都會(huì)自動(dòng)攜帶標(biāo)簽。

          由于 HTTP HandleFunc 這種形式的處理程序非常受歡迎,并且可以與其他處理程序類型進(jìn)行比較,因此讓我們看一下如何調(diào)整下面的代碼以設(shè)置標(biāo)簽。

          我們的原始代碼將 m 用作 *http.ServeMux(或 *github.com/gorilla/mux.Router),看起來像這樣:m.HandleFunc("/", homeHandler)

          應(yīng)用標(biāo)簽代碼后,它將變?yōu)槿缦滤荆?/p>

          m.HandleFunc("/",?func(w?http.ResponseWriter,?r?*http.Request)?{
          ????labels?:=?pprof.Labels("path",?r.RequestURI,?"request",?"real")
          ????pprof.Do(context.Background(),?labels,?func(_?context.Context)?{
          ????????homeHandler(w,?r)
          ????})
          })

          這將標(biāo)記處理每個(gè) HTTP 請(qǐng)求的 goroutine,如下所示。

          debugging http middleware with labels

          由于可以訪問請(qǐng)求對(duì)象,因此可以使用比示例代碼中更復(fù)雜的數(shù)據(jù)填充標(biāo)簽。

          在命令行下使用

          如果直接在命令行中使用 Delve,則需要使用 1867862[1] 或更高版本的 Delve。這些更改將包含在下一個(gè)版本中,而當(dāng)前v1.4.0 版本中未包含。

          要查看標(biāo)簽,請(qǐng)?jiān)谡{(diào)試會(huì)話期間調(diào)用 goroutines -l 命令,以查看到與 IDE 中相同的數(shù)據(jù)。

          debugger dlv from command line with labels

          性能影響

          隨之而來的自然問題是:使用上述代碼對(duì)性能會(huì)有影響嗎?

          答案是肯定的,設(shè)置這些標(biāo)簽確實(shí)會(huì)降低性能。通常,它的影響很小,但是仍然會(huì)存在,因此最好使用一些基準(zhǔn)測(cè)試代碼在自己的硬件上進(jìn)行測(cè)試。

          考慮到這種影響,就會(huì)出現(xiàn)下一個(gè)問題:如果涉及性能,則意味著每次需要進(jìn)行調(diào)試時(shí),我都需要應(yīng)用和撤消代碼。這會(huì)影響我的開發(fā)速度,這能做得更好嗎?

          使用自定義庫啟用調(diào)試標(biāo)簽

          要回答上述問題并允許我們的調(diào)試代碼在不影響性能的情況下進(jìn)行編譯,請(qǐng)使用 github.com/dlsniper/debugger[2] 庫并更改我們的 makeRequest 代碼以包括以下函數(shù)調(diào)用:

          func?makeRequest(done?chan?struct{},?c?*http.Client,?page?string,?i?int64)?{
          ????defer?func()?{
          ????????//?Unblock?the?next?request?from?the?queue
          ????????<-done
          ????}()
          ?
          ????debugger.SetLabels(func()?[]string?{
          ????????return?[]string{
          ????????????"request",?"automated",
          ????????????"page",?page,
          ????????????"rid",?strconv.Itoa(int(i)),
          ????????}
          ????})
          ?//?..
          }

          在調(diào)試器中運(yùn)行此代碼之前,我們需要進(jìn)行其他更改。我們需要在運(yùn)行配置的 Go 工具參數(shù)字段中添加 -tags debugger。否則,該庫將加載生產(chǎn)代碼,標(biāo)簽將不起作用。

          debugger - run configuration

          此處顯示的庫支持標(biāo)準(zhǔn)的 http.HandlerFunc 簽名,以方便在現(xiàn)有應(yīng)用程序中使用。

          回到我們的代碼,如下所示:m.HandleFunc("/", homeHandler)

          要將標(biāo)簽添加到這些處理程序,我們可以將代碼更改為如下所示:

          m.HandleFunc("/",?debugger.Middleware(homeHandler,?func(r?*http.Request)?[]string?{
          ????return?[]string{
          ????????"request",?"real",
          ????????"path",?r.RequestURI,
          ????}
          }))

          專業(yè)提示:

          在單個(gè)函數(shù)或方法中對(duì) debugger.SetLabels[3] 函數(shù)進(jìn)行多次調(diào)用,可以更輕松地跟蹤執(zhí)行進(jìn)度并過濾掉不需要的數(shù)據(jù)。

          專業(yè)提示:

          可以復(fù)制運(yùn)行配置,從而可以在有和沒有調(diào)試器構(gòu)建標(biāo)記(build tag)的情況下使用代碼。

          注意:

          如上所示,設(shè)置標(biāo)簽會(huì)導(dǎo)致性能下降。因此,僅在對(duì)性能要求不高的環(huán)境中使用 -tags=debugger 構(gòu)建的二進(jìn)制文件,或確保通過改善調(diào)試體驗(yàn)來抵消性能損失。

          今天就這樣。我們學(xué)習(xí)了如何使用 GoLand 調(diào)試復(fù)雜的 Go 應(yīng)用程序并在 goroutine 中添加標(biāo)簽,從而使生活變得更輕松。

          這篇文章中的所有代碼都可以在 github.com/dlsniper/debugger[4] 上找到。用于測(cè)試該庫的示例代碼可在 ?github.com/dlsniper/serverdemo[5] 上找到。

          作者:Florin P??an[6]

          原文鏈接:https://blog.jetbrains.com/go/2020/03/03/how-to-find-goroutines-during-debugging/

          編譯:polaris

          參考資料

          [1]

          1867862: https://github.com/go-delve/delve/commit/186786235fc9c2bd9b16c26bb4b0aef60ffb731c

          [2]

          github.com/dlsniper/debugger: https://github.com/dlsniper/debugger

          [3]

          debugger.SetLabels: https://pkg.go.dev/github.com/dlsniper/debugger?tab=doc#SetLabels

          [4]

          github.com/dlsniper/debugger: https://github.com/dlsniper/debugger

          [5]

          github.com/dlsniper/serverdemo: https://github.com/dlsniper/serverdemo

          [6]

          Florin P??an: https://blog.jetbrains.com/go/author/florin-patanjetbrains-com/



          推薦閱讀


          福利

          我為大家整理了一份從入門到進(jìn)階的Go學(xué)習(xí)資料禮包,包含學(xué)習(xí)建議:入門看什么,進(jìn)階看什么。關(guān)注公眾號(hào) 「polarisxu」,回復(fù) ebook 獲取;還可以回復(fù)「進(jìn)群」,和數(shù)萬 Gopher 交流學(xué)習(xí)。

          瀏覽 44
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产综合久久7777777 | 东京热在线观看 | 是先锋男人的网站 | 久久免费视频精品 | 老汉AV在线 |