A Bite of GoLang (5)

叁叁肆2018-09-19 11:19


本文来自网易云社区


作者:盛国存


7.2、使用pprof进行性能调优

上面我们刚提到了性能测试,下一步自然就是我们该如何优化代码的性能,这里我们需要介绍一下Go语言的性能分析工具 pprof ,就依然用上面的这个例子进行阐述它的基本用法,我们要是想了解一段代码具体它慢在哪里,首先呢我们先让它生成一个cpuprofile

sheng$ go test -bench . -cpuprofile=cpu.out
goos: darwin
goarch: amd64
pkg: shengguocun.com/functional/calculator
BenchmarkAdd-4       2000000000             0.34 ns/op
PASS
ok      shengguocun.com/functional/calculator    0.916s

这时候我们发现现在多了一个 cpu.out 文件

sheng$ ls
a.out        add.go        add_test.go    calculator.test    cpu.out

查看之后你会发现是一个二进制文件,那我们该如何处理呢?Go语言的 pprof 就要登场了

sheng$ less cpu.out
"cpu.out" may be a binary file.  See it anyway?
sheng$ go tool pprof cpu.out
Main binary filename not available.
Type: cpu
Time: May 9, 2018 at 5:40pm (CST)
Duration: 907.82ms, Total samples = 600ms (66.09%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)

这时候出现了一个交互式的命令行,我们可以通过输入 help 得到相关的使用说明

(pprof) help
Commands:
callgrind Outputs a graph in callgrind format
comments Output all profile comments
disasm Output assembly listings annotated with samples
dot Outputs a graph in DOT format
eog Visualize graph through eog
evince Visualize graph through evince
gif Outputs a graph image in GIF format
gv Visualize graph through gv
kcachegrind Visualize report in KCachegrind
list Output annotated source for functions matching regexp
pdf Outputs a graph in PDF format
peek Output callers/callees of functions matching regexp
png Outputs a graph image in PNG format
proto Outputs the profile in compressed protobuf format
ps Outputs a graph in PS format
raw Outputs a text representation of the raw profile
svg Outputs a graph in SVG format
tags Outputs all tags in the profile
text Outputs top entries in text form
top Outputs top entries in text form
topproto Outputs top entries in compressed protobuf format
traces Outputs all profile samples in text form
tree Outputs a text rendering of call graph
web Visualize graph through web browser
weblist Display annotated source in a web browser
o/options List options and their current values
quit/exit/^D Exit pprof

Options:
call_tree Create a context-sensitive call tree
compact_labels Show minimal headers
divide_by Ratio to divide all samples before visualization
drop_negative Ignore negative differences
edgefraction Hide edges below <f>*total
focus Restricts to samples going through a node matching regexp
hide Skips nodes matching regexp
ignore Skips paths going through any nodes matching regexp
mean Average sample value over first value (count)
nodecount Max number of nodes to show
nodefraction Hide nodes below <f>*total
normalize Scales profile based on the base profile.
output Output filename for file-based outputs
positive_percentages Ignore negative samples when computing percentages
prune_from Drops any functions below the matched frame.
relative_percentages Show percentages relative to focused subgraph
sample_index Sample value to report (0-based index or name)
show Only show nodes matching regexp
source_path Search path for source files
tagfocus Restricts to samples with tags in range or matched by regexp
taghide Skip tags matching this regexp
tagignore Discard samples with tags in range or matched by regexp
tagshow Only consider tags matching this regexp
trim Honor nodefraction/edgefraction/nodecount defaults
unit Measurement units to display

Option groups (only set one per group):
cumulative
cum Sort entries based on cumulative weight
flat Sort entries based on own weight
granularity
addresses Aggregate at the function level.
addressnoinlines Aggregate at the function level, including functions' addresses in the output.
files Aggregate at the file level.
functions Aggregate at the function level.
lines Aggregate at the source code line level.
noinlines Aggregate at the function level.
: Clear focus/ignore/hide/tagfocus/tagignore

type "help <cmd|option>" for more information
(pprof)

我们这里就介绍一个最简单的方式,敲入web回车,z这里做一个温馨提示

(pprof) web
Failed to execute dot. Is Graphviz installed? Error: exec: "dot": executable file not found in $PATH

出现上述报错的,是因为Graphviz没有安装,安装好了之后再敲入web会生成一个SVG文件,用浏览器打开它

一张图可以很明显的表现出哪边花的时间多哪边花的时间少,当然也可以从框框的大小来做判断,我们需要优化比较大的框框的部分。上述的代码因为太过于简单,大家可以试着用自己写的代码进行性能分析。


7.3、生成文档和事例代码

在我们实际的开发过程中,文档的重要性不必多说,服务调用方、协同开发的小伙伴、QA都需要文档;其他的语言我们经常需要依赖其他的文档工具,比如:ApiDoc、doxmate、daux等等。 首先我们先介绍一下 go doc 的常规的用法

sheng$ go doc
package calculator // import "shengguocun.com/functional/calculator"

func Add(a, b int32) int32
sheng$ go doc Add
func Add(a, b int32) int32

除此之外呢,我们可以通过help来查看

sheng$ go help doc
usage: go doc [-u] [-c] [package|[package.]symbol[.methodOrField]]

Doc prints the documentation comments associated with the item identified by its
arguments (a package, const, func, type, var, method, or struct field)
followed by a one-line summary of each of the first-level items "under"
that item (package-level declarations for a package, methods for a type,
etc.).

Doc accepts zero, one, or two arguments.

Given no arguments, that is, when run as

    go doc

it prints the package documentation for the package in the current directory.
If the package is a command (package main), the exported symbols of the package
are elided from the presentation unless the -cmd flag is provided.

When run with one argument, the argument is treated as a Go-syntax-like
representation of the item to be documented. What the argument selects depends
on what is installed in GOROOT and GOPATH, as well as the form of the argument,
which is schematically one of these:

    go doc <pkg>
    go doc <sym>[.<methodOrField>]
    go doc [<pkg>.]<sym>[.<methodOrField>]
    go doc [<pkg>.][<sym>.]<methodOrField>

The first item in this list matched by the argument is the one whose documentation
is printed. (See the examples below.) However, if the argument starts with a capital
letter it is assumed to identify a symbol or method in the current directory.

For packages, the order of scanning is determined lexically in breadth-first order.
That is, the package presented is the one that matches the search and is nearest
the root and lexically first at its level of the hierarchy. The GOROOT tree is
always scanned in its entirety before GOPATH.

If there is no package specified or matched, the package in the current
directory is selected, so "go doc Foo" shows the documentation for symbol Foo in
the current package.

The package path must be either a qualified path or a proper suffix of a
path. The go tool's usual package mechanism does not apply: package path
elements like . and ... are not implemented by go doc.

When run with two arguments, the first must be a full package path (not just a
suffix), and the second is a symbol, or symbol with method or struct field.
This is similar to the syntax accepted by godoc:

    go doc <pkg> <sym>[.<methodOrField>]

In all forms, when matching symbols, lower-case letters in the argument match
either case but upper-case letters match exactly. This means that there may be
multiple matches of a lower-case argument in a package if different symbols have
different cases. If this occurs, documentation for all matches is printed.

Examples:
    go doc
        Show documentation for current package.
    go doc Foo
        Show documentation for Foo in the current package.
        (Foo starts with a capital letter so it cannot match
        a package path.)
    go doc encoding/json
        Show documentation for the encoding/json package.
    go doc json
        Shorthand for encoding/json.
    go doc json.Number (or go doc json.number)
        Show documentation and method summary for json.Number.
    go doc json.Number.Int64 (or go doc json.number.int64)
        Show documentation for json.Number's Int64 method.
    go doc cmd/doc
        Show package docs for the doc command.
    go doc -cmd cmd/doc
        Show package docs and exported symbols within the doc command.
    go doc template.new
        Show documentation for html/template's New function.
        (html/template is lexically before text/template)
    go doc text/template.new # One argument
        Show documentation for text/template's New function.
    go doc text/template new # Two arguments
        Show documentation for text/template's New function.

    At least in the current tree, these invocations all print the
    documentation for json.Decoder's Decode method:

    go doc json.Decoder.Decode
    go doc json.decoder.decode
    go doc json.decode
    cd go/src/encoding/json; go doc decode

Flags:
    -c
        Respect case when matching symbols.
    -cmd
        Treat a command (package main) like a regular package.
        Otherwise package main's exported symbols are hidden
        when showing the package's top-level documentation.
    -u
        Show documentation for unexported as well as exported
        symbols, methods, and fields.

再比如我们可以查看系统的文档

sheng$ go doc json.Decoder.Decode
func (dec *Decoder) Decode(v interface{}) error
    Decode reads the next JSON-encoded value from its input and stores it in the
    value pointed to by v.

    See the documentation for Unmarshal for details about the conversion of JSON
    into a Go value.

sheng$ go doc fmt.Printf
func Printf(format string, a ...interface{}) (n int, err error)
    Printf formats according to a format specifier and writes to standard
    output. It returns the number of bytes written and any write error
    encountered.

当然我们最常用的命令是 godoc ,我们help看一下它的基本用法

sheng$ godoc -help
usage: godoc package [name ...]
    godoc -http=:6060
  -analysis string
        comma-separated list of analyses to perform (supported: type, pointer). See http://golang.org/lib/godoc/analysis/help.html
  -ex
        show examples in command line mode
  -goroot string
        Go root directory (default "/usr/local/Cellar/go/1.10.2/libexec")
  -html
        print HTML in command-line mode
  -http string
        HTTP service address (e.g., ':6060')
  -httptest.serve string
        if non-empty, httptest.NewServer serves on this address and blocks
  -index
        enable search index
  -index_files string
        glob pattern specifying index files; if not empty, the index is read from these files in sorted order
  -index_interval duration
        interval of indexing; 0 for default (5m), negative to only index once at startup
  -index_throttle float
        index throttle value; 0.0 = no time allocated, 1.0 = full throttle (default 0.75)
  -links
        link identifiers to their declarations (default true)
  -maxresults int
        maximum number of full text search results shown (default 10000)
  -notes string
        regular expression matching note markers to show (default "BUG")
  -play
        enable playground in web interface
  -q    arguments are considered search queries
  -server string
        webserver address for command line searches
  -src
        print (exported) source in command-line mode
  -tabwidth int
        tab width (default 4)
  -templates string
        load templates/JS/CSS from disk in this directory
  -timestamps
        show timestamps with directory listings
  -url string
        print HTML for named URL
  -v    verbose mode
  -write_index
        write index to a file; the file name must be specified with -index_files
  -zip string
        zip file providing the file system to serve; disabled if empty

我们看到有个http的用法,现在我们试一下

sheng$ godoc -http :6060

打开浏览器,输入 http://localhost:6060

完整的Web版的Go语言的文档就可以使用了。当然不单单包含系统函数,同时还包含我们自己写的函数的文档,现在我们就演示一下

// 加法函数
func Add(a, b int32) int32 {

    return a + b
}

我们在函数前面加上了注释,这是我们重新启动 godoc -http :6060 我们会发现

相关的注释已经加上了。Go语言除此之外还提供了写示例代码的方法

func ExampleAdd() {

    c := Add(1, 3)
    fmt.Println(c)

    // Output:
    // 1
}

直接添加一个 ExampleAdd 函数,还是像之前一样写代码,最后我们要写一个 Output 的注释,那你现在是否有疑问,下面的 1 是什么意思?这里说下,这是我随便写的,这时候 Run Test 这段代码

=== RUN   ExampleAdd
--- FAIL: ExampleAdd (0.00s)
got:
4
want:
1
FAIL

Process finished with exit code 1

我们再把正确的输出贴到上面的输出中,重启godoc

这时候完整的示例代码就已经生成到文档中了。

网易云免费体验馆0成本体验20+款云产品!

更多网易研发、产品、运营经验分享请访问网易云社区