中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go語言開發(八)、Go語言程序測試與性能調優

發布時間:2020-06-28 22:42:28 來源:網絡 閱讀:29179 作者:天山老妖S 欄目:編程語言

Go語言開發(八)、Go語言程序測試與性能調優

一、Go語言自動化測試框架簡介

1、自動化測試框架簡介

go語言標準包的testing提供了單元測試(功能性測試)和性能測試(壓力測試)常用方法的框架,可以非常方便地利用其進行自動化測試。
go語言測試代碼只需要放到以?_test.go?結尾的文件中即可。golang的測試分為單元測試和性能測試,單元測試的測試用例必須以Test開頭,其后的函數名不能以小寫字母開頭;性能測試必須以Benchmark開頭,其后的函數名不能以小寫字母開頭。為了測試方法和被測試方法的可讀性,一般Test或Benchmark后為被測試方法的函數名。測試代碼通常與測試對象文件在同一目錄下。

2、單元測試

Go語言單元測試的測試用例必須以Test開頭,其后的函數名不能以小寫字母開頭。
add.go文件:

package add

func add(a,b int)int{
   return a + b
}

單元測試用例:

package add

import "testing"

func TestAdd(t *testing.T){
   sum := add(1,2)
   if sum == 3 {

      t.Logf("add(1,2) == %d",sum)
   }
}

上述代碼測試數據與測試邏輯混合在一起,根據Go語言的特點和工程實踐,產生了一種表格驅動測試方法。表格驅動測試將測試數據集中保存在切片中,測試數據與測試邏輯實現了分離。
表格驅動測試:

package add

import "testing"

func TestAdd(t *testing.T) {
   //定義測試數據
   tests := []struct{ a, b, c int }{
      {3, 4, 7},
      {5, 12, 17},
      {8, 15, 23},
      {12, 35, 47},
      {30000, 40000, 70000},
   }
   //測試邏輯
   for _,tt := range tests{
      if actual := add(tt.a,tt.b);actual != tt.c{
         t.Errorf("Add(%d,%d) got %d;expected %d", tt.a,tt.b,actual,tt.c)
      }
   }
}

表格驅動測試的優點:
A、分離測試數據和測試邏輯
B、明確出錯信息
C、可以部分失敗
D、Go語言更容易實現表格驅動測試
執行測試:
go test
結果如下:

[user@localhost test]$ go test -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
PASS
ok      _/home/user/GoLang/test 0.001s

3、性能測試

性能測試即壓力測試(BMT: Benchmark Testing)。
性能測試用例:

func BenchmarkAdd(t *testing.B){

   //重置時間點
   t.ResetTimer()
   for i := 0; i < t.N; i++{
      add(1,2)
   }
}

完整測試代碼如下:

package add

import "testing"

func TestAdd(t *testing.T) {
   //定義測試數據
   tests := []struct{ a, b, c int }{
      {3, 4, 7},
      {5, 12, 17},
      {8, 15, 23},
      {12, 35, 47},
      {30000, 40000, 70000},
   }
   //測試邏輯
   for _,tt := range tests{
      if actual := add(tt.a,tt.b);actual != tt.c{
         t.Errorf("Add(%d,%d) got %d;expected %d", tt.a,tt.b,actual,tt.c)
      }
   }
}

func BenchmarkAdd(t *testing.B){

   //重置時間點
   t.ResetTimer()
   for i := 0; i < t.N; i++{
      add(1,2)
   }
}

執行測試:
go test -bench=.
結果如下:

[user@localhost test]$ go test -bench=.
goos: linux
goarch: amd64
BenchmarkAdd-4      2000000000           0.38 ns/op
PASS
ok      _/home/user/GoLang/test 0.803s

4、代碼覆蓋率測試

測試覆蓋率是用于通過執行某包的測試用例來確認到的描述其的代碼在測試用例中被執行的程度的術語。
在go語言的測試覆蓋率統計時,go test通過參數covermode的設定可以對覆蓋率統計模式作如下三種設定:
A、set:缺省模式, 只記錄語句是否被執行過
B、count:記錄語句被執行的次數
C、atomic:記錄語句被執行的次數,并保證在并發執行時的正確性
執行覆蓋率測試:
go test -cover
結果如下:

[user@localhost test]$ go test -cover
PASS
coverage: 100.0% of statements
ok      _/home/user/GoLang/test 0.001s

執行命令,生成代碼覆蓋率測試信息:
go test -coverprofile=covprofile
查看covprofile文件信息:

[user@localhost test]$ cat covprofile 
mode: set
_/home/user/GoLang/test/add.go:3.21,5.2 1 1
[user@localhost test]$ 

將生成代碼覆蓋率測試信息轉換為HTML格式:
go tool cover -html=covprofile -o coverage.html
使用瀏覽器查看coverage.html文件。

二、go tool pprof性能分析工具

1、go tool pprof簡介

Golang內置cpu、mem、block三種profiler采樣工具,允許程序在運行時使用profiler進行數據采樣,生成采樣文件。通過go tool pprof工具可以交互式分析采樣文件,得到高可讀性的輸出信息。
任何以go tool開頭的Go命令內部指向的特殊工具都被保存在目錄$GOROOT/pkg/tool/$GOOS_$GOARCH/目錄,即Go工具目錄。pprof工具并不是用Go語言編寫的,而是由Perl語言編寫。Perl語言可以直接讀取源碼并運行。因此,pprof工具的源碼文件被直接保存在Go工具目錄下。
pprof工具是用Perl語言編寫的,執行go tool pprof命令的前提條件是需要在當前環境下安裝Perl語言
go tool pprof命令會分析指定的概要文件并使得能夠以交互式的方式訪問其中的信息。但只有概要文件還不夠,還需要概要文件中信息的來源——命令源碼文件的可執行文件。而可以運行的Go語言程序只能是編譯命令源碼文件后生成的可執行文件。

2、profile采樣文件簡介

在Go語言中,可以通過標準庫的代碼包runtime和runtime/pprof中的程序來生成三種包含實時性數據的概要文件,分別是CPU概要文件、內存概要文件和程序阻塞概要文件。
A、CPU概要文件
CPU的主頻,即CPU內核工作的時鐘頻率(CPU Clock Speed)。CPU的主頻的基本單位是赫茲(Hz)。時鐘頻率的倒數即為時鐘周期。在一個時鐘周期內,CPU執行一條運算指令。在1000 Hz的CPU主頻下,每1毫秒可以執行一條CPU運算指令;在1 MHz的CPU主頻下,每1微妙可以執行一條CPU運算指令;在1 GHz的CPU主頻下,每1納秒可以執行一條CPU運算指令。
在默認情況下,Go語言的運行時系統會以100 Hz的的頻率對CPU使用情況進行取樣,即每秒取樣100次(每10毫秒會取樣一次)。100 Hz既足夠產生有用的數據,又不至于讓系統產生停頓,并且100容易做換算。對CPU使用情況的取樣就是對當前的Goroutine的堆棧上的程序計數器的取樣。由此,可以從樣本記錄中分析出哪些代碼是計算時間最長或者說最耗CPU資源的部分。可以通過以下代碼啟動對CPU使用情況的記錄。

func startCPUProfile() {
   if *cpuProfile != "" {
      f, err := os.Create(*cpuProfile)
      if err != nil {
         fmt.Fprintf(os.Stderr, "Can not create cpu profile output file: %s",
            err)
         return
      }
      if err := pprof.StartCPUProfile(f); err != nil {
         fmt.Fprintf(os.Stderr, "Can not start cpu profile: %s", err)
         f.Close()
         return
      }
   }
}

在函數startCPUProfile中,首先創建了一個用于存放CPU使用情況記錄的文件,即CPU概要文件,其絕對路徑由*cpuProfile的值表示。然后,把profile文件的實例作為參數傳入到函數pprof.StartCPUProfile中。如果pprof.StartCPUProfile函數沒有返回錯誤,說明記錄操作已經開始。只有CPU概要文件的絕對路徑有效時,pprof.StartCPUProfile函數才會開啟記錄操作。
如果想要在某一時刻停止CPU使用情況記錄操作,需要調用以下函數:

func stopCPUProfile() {
   if *cpuProfile != "" {
      pprof.StopCPUProfile() // 把記錄的概要信息寫到已指定的文件
   }
}

在以上函數中,并沒有代碼用于CPU概要文件寫入操作。在啟動CPU使用情況記錄操作后,運行時系統就會以每秒100次的頻率將采樣數據寫入到CPU概要文件中。pprof.StopCPUProfile函數通過把CPU使用情況取樣的頻率設置為0來停止取樣操作。只有當所有CPU使用情況記錄都被寫入到CPU概要文件后,pprof.StopCPUProfile函數才會退出,保證CPU概要文件的完整性。
B、內存概要文件
內存概要文件用于保存在用戶程序執行期間的內存使用情況,即程序運行過程中堆內存的分配情況。Go語言運行時系統會對用戶程序運行期間的所有的堆內存分配進行記錄。不論在取樣的哪一時刻、堆內存已用字節數是否有增長,只要有字節被分配且數量足夠,分析器就會對其進行取樣。開啟內存使用情況記錄的可以使用以下函數:

func startMemProfile() {
   if *memProfile != "" && *memProfileRate > 0 {
      runtime.MemProfileRate = *memProfileRate
   }
}

開啟內存使用情況記錄的方式非常簡單。在函數startMemProfile中,只有在memProfile和memProfileRate的值有效時才會進行后續操作。memProfile的含義是內存概要文件的絕對路徑。memProfileRate的含義是分析器的取樣間隔,單位是字節。當將memProfileRate值賦給int類型的變量runtime.MemProfileRate時,意味著分析器將會在每分配指定的字節數量后對內存使用情況進行取樣。實際上,即使不給runtime.MemProfileRate變量賦值,內存使用情況的取樣操作也會照樣進行。此取樣操作會從用戶程序開始時啟動,且一直持續進行到用戶程序結束。runtime.MemProfileRate變量的默認值是512 1024,即512K個字節。只有當顯式的將0賦給runtime.MemProfileRate變量后,才會取消取樣操作。
在默認情況下,內存使用情況的取樣數據只會被保存在運行時內存中,而保存到文件的操作只能由開發者自己來完成。取消采樣操作代碼如下:

func stopMemProfile() {
   if *memProfile != "" {
      f, err := os.Create(*memProfile)
      if err != nil {
         fmt.Fprintf(os.Stderr, "Can not create mem profile output file: %s", err)
         return
      }
      if err = pprof.WriteHeapProfile(f); err != nil {
         fmt.Fprintf(os.Stderr, "Can not write %s: %s", *memProfile, err)
      }
      f.Close()
   }
}

stopMemProfile函數的功能是停止對內存使用情況的取樣操作。stopMemProfile只做了將取樣數據保存到內存概要文件的操作。在stopMemProfile函數中,調用函數pprof.WriteHeapProfile,并把代表內存概要文件的文件實例作為參數。如果pprof.WriteHeapProfile函數沒有返回錯誤,就說明數據已被寫入到了內存概要文件中。
對內存使用情況進行取樣的程序會假定取樣間隔在用戶程序的運行期間內都是一成不變的,并且等于runtime.MemProfileRate變量的當前值。因此,應該在Go程序中只改變內存取樣間隔一次,且應盡早改變。比如,在命令源碼文件的main函數的開始處就改變內存采樣間隔。
C、程序阻塞概要文件
程序阻塞概要文件用于保存用戶程序中的Goroutine阻塞事件的記錄。開啟程序阻塞采樣的代碼如下:

func startBlockProfile() {
   if *blockProfile != "" && *blockProfileRate > 0 {
      runtime.SetBlockProfileRate(*blockProfileRate)
   }
}

在函數startBlockProfile中,當blockProfile和blockProfileRate的值有效時,會設置對Goroutine阻塞事件的取樣間隔。blockProfile的含義為程序阻塞概要文件的絕對路徑。blockProfileRate的含義是分析器的取樣間隔,單位是次。函數runtime.SetBlockProfileRate的唯一參數是int類型的,含義是分析器會在每發生幾次Goroutine阻塞事件時對阻塞事件進行取樣。如果不顯式的使用runtime.SetBlockProfileRate函數設置取樣間隔,那么取樣間隔就為1。即在默認情況下,每發生一次Goroutine阻塞事件,分析器就會取樣一次。運行時系統對Goroutine阻塞事件的取樣操作也會貫穿于用戶程序的整個運行期。但是,如果通過runtime.SetBlockProfileRate函數將取樣間隔設置為0或者負數,那么取樣操作就會被取消。
在程序結束前可以將被保存在運行時內存中的Goroutine阻塞事件記錄存放到指定的文件中。代碼如下:

func stopBlockProfile() {
   if *blockProfile != "" && *blockProfileRate >= 0 {
      f, err := os.Create(*blockProfile)
      if err != nil {
         fmt.Fprintf(os.Stderr, "Can not create block profile output file: %s", err)
         return
      }
      if err = pprof.Lookup("block").WriteTo(f, 0); err != nil {
         fmt.Fprintf(os.Stderr, "Can not write %s: %s", *blockProfile, err)
      }
      f.Close()
   }
}

在創建程序阻塞概要文件后,stopBlockProfile函數會先通過函數pprof.Lookup將保存在運行時內存中的內存使用情況記錄取出,并在記錄的實例上調用WriteTo方法將記錄寫入到文件中。

3、profiling使用場景

A、基準測試
使用go test -bench . -cpuprofile prof.cpu生成基準測試的采樣文件,再通過命令go tool pprof [binary] prof.cpu對采樣文件進行分析。
B、Web服務測試
如果應用是一個web服務,可以在http服務啟動的代碼文件添加import _ net/http/pprof,Web服務會自動開啟profile功能,輔助開發者直接分析采樣結果。可以在瀏覽器中使用http://localhost:port/debug/pprof/直接看到當前web服務的狀態,包括CPU占用情況和內存使用情況等。
C、應用程序
如果go程序是一個應用程序,不能使用net/http/pprof包,需要使用runtime/pprof包。使用pprof.StartCPUProfile、pprof.StopCPUProfile或是內存采樣、阻塞采樣接口等對運行時信息進行采樣。最終使用go tool pprof工具對采樣文件進行分析。
D、服務進程
如果go程序不是web服務器,而是一個服務進程,那么也可以選擇使用net/http/pprof包,同樣引入包net/http/pprof,然后再開啟另外一個goroutine來開啟端口監聽。

go func() {
   log.Println(http.ListenAndServe("localhost:6666", nil))
}()

4、pprof使用

編寫一個簡單的應用程序,使用pprof.StartCPUProfile和pprof.StopCPUProfile對CPU信息進行采樣。

package main

import (
   "flag"
   "log"
   "os"
   "runtime/pprof"
   "fmt"
)

// 斐波納契數列
func Fibonacci() func() int {
   back1, back2 := 1, 1
   return func() int {
      //重新賦值
      back1, back2 = back2, (back1 + back2)
      return back1
   }
}

func count(){
    a := 0;
   for i := 0; i < 10000000000; i++ {
      a = a + i
   }
}

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")

func main() {
   flag.Parse()
   if *cpuprofile != "" {
      f, err := os.Create(*cpuprofile)
      if err != nil {
         log.Fatal(err)
      }
      pprof.StartCPUProfile(f)
      defer f.Close()
   }
   fibonacci := Fibonacci()
   for i := 0; i < 100; i++ {
      fmt.Println(fibonacci())
   }
   count()

   defer pprof.StopCPUProfile()
}

進行運行時信息采樣時,可以指定不同的采樣參數:
--cpuprofile:指定CPU概要文件的保存路徑
--blockprofile:指定程序阻塞概要文件的保存路徑。
--blockprofilerate:定義其值為n,指定每發生n次Goroutine阻塞事件時,進行一次取樣操作。
--memprofile:指定內存概要文件的保存路徑。
--memprofilerate:定義其值為n,指定每分配n個字節的堆內存時,進行一次取樣操作。
運行go程序,對CPU信息進行采樣:
go run fibonacci.go --cpuprofile=profile.cpu
分析CPU采樣文件profile.cpu:
go tool pprof profile.cpu
Go語言開發(八)、Go語言程序測試與性能調優
如果Go程序非常簡單,比如只有fibonacci()函數調用(注釋count()函數),使用pprof.StartCPUProfile是打印不出任何信息的。
默認情況下top命令會列出前10項內容。可以top命令后面緊跟一個數字,限制列出的項數。
Go語言開發(八)、Go語言程序測試與性能調優

三、go-torch性能分析工具

1、go-torch簡介

go-torch是Uber公司開源的一款針對Golang程序的火焰圖生成工具,能收集stack traces,整理成火焰圖,并直觀地顯示程序給開發人員。go-torch是基于使用BrendanGregg創建的火焰圖工具生成直觀的圖像,方便地分析Go的各個方法所占用CPU的時間。

2、FlameGraph安裝

git clone https://github.com/brendangregg/FlameGraph.git
sudo cp FlameGraph/flamegraph.pl /usr/local/bin
在終端輸入flamegraph.pl -h測試FlameGraph是否安裝成功

3、go-torch安裝

go get -v github.com/uber/go-torch
go-torch默認安裝在GOPATH指定的第一個目錄中,位于bin目錄下。

4、go-wrk壓力測試

安裝go-wrk壓力測試工具:
go get -v github.com/adjust/go-wrk
執行35s 1W次高并發場景模擬:
go-wrk -d 35 -n 10000 http://localhost:port/demo

5、go-torch使用

在Web服務壓力測試過程中,使用go-torch生成采樣文件。
go-torch -u http://localhost:port -t 30
go-torch完成采樣時輸出如下信息:
Writing svg to torch.svg
torch.svg是go-torch自動生成的profile文件,使用瀏覽器打開如下:
Go語言開發(八)、Go語言程序測試與性能調優
火焰圖的y軸表示cpu調用方法的先后,x軸表示在每個采樣調用時間內,方法所占的時間百分比,越寬代表占據cpu時間越多。
根據火焰圖可以清楚的查看哪個方法調用耗時長,然后不斷的修正代碼,重新采樣,不斷優化。

四、Go語言程序性能優化

1、內存優化

A、將小對象合并成結構體一次分配,減少內存分配次數
Go runtime底層采用內存池機制,每個span大小為4k,同時維護一個cache。cache有一個0到n的list數組,list數組的每個單元掛載的是一個鏈表,鏈表的每個節點就是一塊可用的內存塊,同一鏈表中的所有節點內存塊都是大小相等的;但是不同鏈表的內存大小是不等的,即list數組的一個單元存儲的是一類固定大小的內存塊,不同單元里存儲的內存塊大小是不等的。cache緩存的是不同類大小的內存對象,申請的內存大小最接近于哪類緩存內存塊時,就分配哪類內存塊。當cache不夠時再向spanalloc中分配。
B、緩存區內容一次分配足夠大小空間,并適當復用
在協議編解碼時,需要頻繁地操作[]byte,可以使用bytes.Buffer或其它byte緩存區對象。
bytes.Buffer等通過預先分配足夠大的內存,避免當增長時動態申請內存,減少內存分配次數。對于byte緩存區對象需要考慮適當地復用。
C、slice和map采make創建時,預估大小指定容量
slice和map與數組不一樣,不存在固定空間大小,可以根據增加元素來動態擴容。
slice初始會指定一個數組,當對slice進行append等操作時,當容量不夠時,會自動擴容:
如果新的大小是當前大小2倍以上,則容量增漲為新的大小;
否則循環以下操作:如果當前容量小于1024,按2倍增加;否則每次按當前容量1/4增漲,直到增漲的容量超過或等新大小。
map的擴容比較復雜,每次擴容會增加到上次容量的2倍。map的結構體中有一個buckets和oldbuckets,用于實現增量擴容:
正常情況下,直接使用buckets,oldbuckets為空;
如果正在擴容,則oldbuckets不為空,buckets是oldbuckets的2倍,
因此,建議初始化時預估大小指定容量
D、長調用棧避免申請較多的臨時對象
Goroutine的調用棧默認大小是4K(1.7修改為2K),采用連續棧機制,當棧空間不夠時,Go runtime會自動擴容:
當棧空間不夠時,按2倍增加,原有棧的變量會直接copy到新的棧空間,變量指針指向新的空間地址;
退棧會釋放棧空間的占用,GC時發現棧空間占用不到1/4時,則棧空間減少一半。
比如棧的最終大小2M,則極端情況下,就會有10次的擴棧操作,會帶來性能下降。
因此,建議控制調用棧和函數的復雜度,不要在一個goroutine做完所有邏輯;如的確需要長調用棧,而考慮goroutine池化,避免頻繁創建goroutine帶來棧空間的變化。
E、避免頻繁創建臨時對象
Go在GC時會引發stop the world,即整個情況暫停。Go1.8最壞情況下GC為100us。但暫停時間還是取決于臨時對象的個數,臨時對象數量越多,暫停時間可能越長,并消耗CPU。
因此,建議GC優化方式是盡可能地減少臨時對象的個數:盡量使用局部變量;所多個局部變量合并一個大的結構體或數組,減少掃描對象的次數,一次回盡可能多的內存。

2、并發優化

A、高并發的任務處理使用goroutine池
Goroutine雖然輕量,但對于高并發的輕量任務處理,頻繁來創建goroutine來執行,執行效率并不會太高,因為:過多的goroutine創建,會影響go runtime對goroutine調度,以及GC消耗;高并發時若出現調用異常阻塞積壓,大量的goroutine短時間積壓可能導致程序崩潰。
B、避免高并發調用同步系統接口
goroutine的實現,是通過同步來模擬異步操作。
網絡IO、鎖、channel、Time.sleep、基于底層系統異步調用的Syscall操作并不會阻塞go runtime的線程調度。
本地IO調用、基于底層系統同步調用的Syscall、CGo方式調用C語言動態庫中的調用IO或其它阻塞會創建新的調度線程。
網絡IO可以基于epoll的異步機制(或kqueue等異步機制),但對于一些系統函數并沒有提供異步機制。例如常見的posix api中,對文件的操作就是同步操作。雖有開源的fileepoll來模擬異步文件操作。但Go的Syscall還是依賴底層的操作系統的API。系統API沒有異步,Go也做不了異步化處理。
因此,建議:把涉及到同步調用的goroutine,隔離到可控的goroutine中,而不是直接高并的goroutine調用。
C、高并發時避免共享對象互斥
傳統多線程編程時,當并發沖突在4~8線程時,性能可能會出現拐點。Go推薦不通過共享內存來通信,Go創建goroutine非常容易,當大量goroutine共享同一互斥對象時,也會在某一數量的goroutine出在拐點。
因此,建議:goroutine盡量獨立,無沖突地執行;若goroutine間存在沖突,則可以采分區來控制goroutine的并發個數,減少同一互斥對象沖突并發數。

3、其它優化

A、避免使用CGO或者減少CGO調用次數
GO可以調用C庫函數,但Go帶有垃圾收集器且Go的棧動態增漲,無法與C無縫地對接。Go的環境轉入C代碼執行前,必須為C創建一個新的調用棧,把棧變量賦值給C調用棧,調用結束現拷貝回來。調用開銷較大,需要維護Go與C的調用上下文,兩者調用棧的映射。相比直接的GO調用棧,單純的調用棧可能有2個甚至3個數量級以上。
因此,建議:盡量避免使用CGO,無法避免時,要減少跨CGO的調用次數。
B、減少[]byte與string之間轉換,盡量采用[]byte來字符串處理
GO里面的string類型是一個不可變類型,GO中[]byte與string底層是兩個不同的結構,轉換存在實實在在的值對象拷貝,所以盡量減少不必要的轉化。
因此,建議:存在字符串拼接等處理,盡量采用[]byte。
C、字符串的拼接優先考慮bytes.Buffer
string類型是一個不可變類型,但拼接會創建新的string。GO中字符串拼接常見有如下幾種方式:
string + 操作 :導致多次對象的分配與值拷貝
fmt.Sprintf :會動態解析參數,效率好不哪去
strings.Join :內部是[]byte的append
bytes.Buffer :可以預先分配大小,減少對象分配與拷貝
因此,建議:對于高性能要求,優先考慮bytes.Buffer,預先分配大小。fmt.Sprintf可以簡化不同類型轉換與拼接。

五、Go程序文檔生成

1、go doc工具簡介

go doc?工具會從Go程序和包文件中提取頂級聲明的首行注釋以及每個對象的相關注釋,并生成相關文檔。
go doc也可以作為一個提供在線文檔瀏覽的web服務器。

2、終端查看文檔

go doc package:獲取包的文檔注釋,例如:go doc fmt?會顯示使用?godoc?生成的?fmt?包的文檔注釋。
go doc package/subpackage:?獲取子包的文檔注釋,例如:go doc container/list。
go doc package function?:獲取某個函數在某個包中的文檔注釋,例如:go doc fmt Printf?會顯示有關?fmt.Printf()?的使用說明。

3、在線瀏覽文檔

godoc支持啟動一個Web在線API文檔服務,在命令行執行:
godoc -http=:6666
啟動Web服務后,使用瀏覽器打開http://127.0.0.1:6666,可以看到本地文檔瀏覽服務器提供的頁面。
Go語言開發(八)、Go語言程序測試與性能調優
經測試,Google Chrome瀏覽器不能訪問godoc開啟的Web服務。

4、生成文檔

Go文檔工具支持開發人員自己寫的代碼,只要開發者按照一定的規則,就可以自動生成文檔。
add.go文件如下:

/*
add function will be add a and b.
return a+b
  */
package add

// add
func add(a,b int)int{
   return a + b
}

生成文文檔如下:

[user@localhost add]$ go doc
package add // import "add"

add function will be add a and b. return a+b

[user@localhost add]$ 

go doc工具會將包文件中頂級聲明的首行注釋提取出來。如果函數為private(函數名稱首字母小寫),go doc工具會隱藏函數。

/*
add function will be add a and b.
return a+b
  */
package add

// add
func Add(a,b int)int{
   return a + b
}

生成文檔如下:

[user@localhost add]$ go doc
package add // import "add"

add function will be add a and b. return a+b

func Add(a, b int) int
[user@localhost add]$ 

5、添加文檔示例

Go語言的文檔中添加示例代碼的步驟如下:
A、示例代碼必須單獨存放在一個文件(文件名字為example_test.go)中或是測試代碼文件中。
B、在示例代碼文件里,定義一個名字為Example的函數,參數為空
C、示例的輸出采用注釋的方式,以// Output:開頭,另起一行,每行輸出占一行。

package add

import (
    "fmt"
)

func Example(){
    sum := add(1,2)
    fmt.Println(sum)
    // Output:
    // 3
}

生成文檔結果如下:
Go語言開發(八)、Go語言程序測試與性能調優

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

龙泉市| 南开区| 扎鲁特旗| 双牌县| 壤塘县| 上高县| 新昌县| 行唐县| 久治县| 杨浦区| 延川县| 鞍山市| 京山县| 任丘市| 姜堰市| 筠连县| 木里| 兰西县| 庄河市| 团风县| 巍山| 永济市| 慈溪市| 邳州市| 扬州市| 永和县| 大埔区| 绥阳县| 兴义市| 海盐县| 台湾省| 兴业县| 闽清县| 屯门区| 涟源市| 闵行区| 临泽县| 龙江县| 封开县| 乌什县| 山阴县|