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

來源:互聯網
上載者:User

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

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

1、自動化測試架構簡介

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

2、單元測試

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

package addfunc add(a,b int)int{   return a + b}

單元測試用例:

package addimport "testing"func TestAdd(t *testing.T){   sum := add(1,2)   if sum == 3 {      t.Logf("add(1,2) == %d",sum)   }}

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

package addimport "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)PASSok      _/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 addimport "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: linuxgoarch: amd64BenchmarkAdd-4      2000000000           0.38 ns/opPASSok      _/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 -coverPASScoverage: 100.0% of statementsok      _/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 mainimport (   "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程式非常簡單,比如只有fibonacci()函數調用(注釋count()函數),使用pprof.StartCPUProfile是列印不出任何資訊的。
預設情況下top命令會列出前10項內容。可以top命令後面緊跟一個數字,限制列出的項數。

三、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檔案,使用瀏覽器開啟如下:

火焰圖的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,可以看到本地文檔瀏覽伺服器提供的頁面。

經測試,Google Chrome瀏覽器不能訪問godoc開啟的Web服務。

4、產生文檔

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

/*add function will be add a and b.return a+b  */package add// addfunc add(a,b int)int{   return a + b}

產生文文檔如下:

[user@localhost add]$ go docpackage 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// addfunc Add(a,b int)int{   return a + b}

產生文檔如下:

[user@localhost add]$ go docpackage add // import "add"add function will be add a and b. return a+bfunc Add(a, b int) int[user@localhost add]$ 

5、添加文檔樣本

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

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

產生文檔結果如下:

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.