- escape analysis 堆和栈,对于C/C++而言auto变量自然分配在栈上而如果需要分配在堆上则需要通过malloc调用来分配内存在 堆上。而对于Go语言来讲编译时候会根据是否有外部引用来判断是否将内存分配在堆或者是栈上。 Five things that make Go fast这篇文章里有详细的叙述。所以对于有些地方直接将类似与C/C++中的 auto变量地址返回的这样的情景请不要惊讶。编译器已经考虑到了。
- Sender close the channel
- using recover() trapped the panic
- format %T get the type
- %q a single-quoted character literal safely escaped with Go syntax.
- trace: GOMAXPROCS=2 GODEBUG=schedtrace=1000,scheddetail=1 ./trace https://www.goinggo.net/2015/02/scheduler-tracing-in-go.html for detail
github.com\rogpeppe\godef\go\parser\parser.go
// p.error(path.Pos(), fmt.Sprintf(“cannot find identifier for package %q: %v”, litToString(path), err))
fixed this
Programs initialize and begin execution from the main package. If the main package imports other packages, they will be imported in the compile time. If one package is imported many times, it will be only compiled once. After importing packages, programs will initialize the constants and variables within the imported packages, then execute the init function if it exists, and so on. After all the other packages are initialized, programs will initialize constants and variables in the main package, then execute the init function inside the package if it exists. The following figure shows the process.
import(
. "fmt"
)
The dot operator means you can omit the package name when you call functions inside of that package. Now `fmt.Printf(“Hello world”)` becomes to `Printf(“Hello world”)`.
if value, ok := element.(int); ok
the answer is in the pathMatch function.
Go is more about software engineering than programming language research. Or to rephrase, it is about language design in the service of software engineering.
Go有两个数据结构创建函数:new和make。两者的区别在学习Go语言的初期是一个常见的混淆点。基本的区别是`new(T)`返回一个`*T`,返回的这个指针可以被隐式地消除引用(图中的黑色箭头)。而`make(T, args)`返回一个普通的T。通常情况下,T内部有一些隐式的指针(图中的灰色箭头)。一句话,new返回一个指向已清零内存的指针,而make返回一个复杂的结构。
方便goroutine的stack
On Linux, it uses epoll, on the BSDs and Darwin, it uses kqueue and on Windows it uses IoCompletionPort.
-gcflags=’-N -l’ 否则local变量会被优化掉不好调试。 1.10以后需要调整为: -gcflags=”all=-N -l”
是单数,不是复数。
https://gist.github.com/the42/1956518
package main
import (
"fmt"
"log"
"net/http"
_ "net/http/pprof" // here be dragons
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
url:
- /debug/pprof/profile: 30-second CPU profile
- /debug/pprof/heap: heap profile
- /debug/pprof/goroutine?debug=1: all goroutines with stack traces
- /debug/pprof/trace: take a trace
Body不关闭,http客户端无法复用tcp连接,导致连接数上涨。需要做到两点:
res, _ := client.Do(req)
io.Copy(ioutil.Discard, res.Body)
res.Body.Close()
即body应当被读取,然后关闭。
gorm need rows.Close()
ps: how to check gorouine leak? https://github.com/fortytw2/leaktest runtime.Stack然后选取感兴趣的即可
https://stackoverflow.com/questions/24537443/meaning-of-a-struct-with-embedded-anonymous-interface
Use long declaration when you can’t know what data to store beforehand, otherwise, use short declaration. Use multiple declaration when you want to define multiple variables together or as an hint for code readability that the variables will be used together.
You can’t use short declarations outside of functions including main function. Or: you will meet with this error: “syntax error: non-declaration statement outside function body”.
log.SetFlags(log.LstdFlags | log.Lshortfile)
许多关于Go调度的上来就是给你GMP,但这里的展开我觉的讲的很好 https://news.ycombinator.com/item?id=12459841 这个也不错, http://morsmachine.dk/go-scheduler
tl,dr : [fn:2]
go get github.com/google/pprof
import (
"runtime/pprof"
)
pprof.StartCPUProfile(os.Stdout)
defer pprof.StopCPUProfile()
生成profile文件之后用tool来inspect:
go tool pprof cpu.profile
内存全量使用情况: go tool pprof -alloc_space http://localhost:6060/debug/pprof/heap 当前情况使用: go tool pprof -inuse_space http://localhost:6060/debug/pprof/heap 保存png文件: apt-get install graphviz go tool pprof -png http://localhost:6060/debug/pprof/heap > data.png 如果是想知道CPU哪里慢了,用pprof 看看goroutine情况的URL http://localhost:6060/debug/pprof/goroutine?debug=1 跟着pprof的一个golang命令行工具: https://github.com/google/gops
strings.NewReader(s)
github.com/rapidloop/rtop 这个repo里有相关方法,可以参考
还是用dlv工具[fn:3]
- go build -x 看看过程都干了啥
- go test -race 死锁检测
- go get -d 只是clone不去安装
- 重置test时间[fn:4] b.ResetTimer() or: b.StopTimer() at some point then b.StartTimer() just brefore the bench you want
- 显示分配内存情况 b.ReportAllocs()
- gen profile -cpuprofile=$FILE writes a CPU profile to $FILE. -memprofile=$FILE, writes a memory profile to $FILE, -memprofilerate=N adjusts the profile rate to 1/N. -blockprofile=$FILE, writes a block profile to $FILE. Using any of these flags also preserves the binary. % go test -run=XXX -bench=. -cpuprofile=c.p bytes % go tool pprof c.p % go test -gcflags=-N -bench=. #禁止编译器优化
编译proto: protoc –go_out=plugins=grpc:. helloworld.proto 定义的proto会生成对应Client/Server的interface, 后面对应server的实现函数signature就需要和interface中指定的一样。 主要是stream这里需要理解一下,可以单向也可以全双工。通过获得stream然后对应读和写操作。
doWork := func(done <-chan interface{}, strchan <-chan string) <-chan interface{} {
terminated := make(chan interface{})
go func() {
defer fmt.Println("doWork exited.")
defer close(terminated)
for {
select {
case s := <-strchan:
fmt.Println(s)
// add this to prevent goroutine leak
case <-done:
return
}
}
}()
return terminated
}
一般都会添加一个done channel用来退出,不妨称为done channel pattern吧。
reflect.TypeOf(s) reflect.ValueOf(s).Kind() fmt.Printf(“%T\n”, s)
interface internel
环境变量都在这里了
To kill a hung Go process and print the current stacks of all goroutines, simply send it an ABRT signal:
kill -ABRT <pid>[fn:5]
https://gitlab.com/gitlab-com/runbooks/blob/master/howto/gitaly-profiling.md
- Statements that don’t return rows should not use Query functions; they should use Exec().
- Although it’s idiomatic to Close() the database when you’re finished with it, the sql.DB object is designed to be long-lived. Don’t Open() and Close() databases frequently. Instead, create one sql.DB object for each distinct datastore you need to access, and keep it until the program is done accessing that datastore.
- prepares, executes, and closes 三部曲
- This also means that prepared statements created inside a Tx can’t be used separately from it. Likewise, prepared statements created on a DB can’t be used within a transaction, because they will be bound to a different connection. placeholder:
MySQL | PostgreSQL | Oracle |
WHERE col = ? | WHERE col = $1 | WHERE col = :col |
VALUES(?, ?, ?) | VALUES($1, $2, $3) | VALUES(:val1, :val2, :val3) |
for rows.Next() {
// ...
}
// always check error
if err = rows.Err(); err != nil {
// handle the error here
}
// You should always explicitly close a sql.Rows if you exit the loop prematurely, as previously mentioned. It’s auto-closed if the loop exits normally or through an error, but you might mistakenly do this:
for rows.Next() {
// ...
break; // whoops, rows is not closed! memory leak...
}
// do the usual "if err = rows.Err()" [omitted here]...
// it's always safe to [re?]close here:
if err = rows.Close(); err != nil {
// but what should we do if there's an error?
log.Println(err)
}
把P看成是一个context,m必须获得p然后才能运行G。: https://news.ycombinator.com/item?id=12460807 这个解释非常到位,一看作者是golang的maintaner,难怪
A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns.
It is not possible to create a Go program where two variables share the same storage location in memory. It is possible to create two variables whose contents point to the same storage location, but that is not the same thing as two variables who share the same storage location.
package main
import "fmt"
func main() {
var a int
var b, c = &a, &a
fmt.Println(b, c) // 0x1040a124 0x1040a124
fmt.Println(&b, &c) // 0x1040c108 0x1040c110
}
==> A map value is a pointer to a runtime.hmap structure.[fn:6]
知道是在main前面但是和变量初始化比呢?顺序如下:
- If a package imports other packages, the imported packages are initialised first.
- Current package’s constant initialized then.
- Current package’s variables are initialiszd then.
- Finally, init() function of current package is called.
- Methods using receiver pointers are common; the rule of thumb for receivers is, “If in doubt, use a pointer.”
- Slices, maps, channels, strings, function values, and interface values are implemented with pointers internally, and a pointer to them is often redundant.
- Elsewhere, use pointers for big structs or structs you’ll have to change, and otherwise pass values, because getting things changed by surprise via a pointer is confusing.
1.8以后用 os.Executable
来做。
The rule about pointers vs. values for receivers is that value methods can be invoked on pointers and values, but pointer methods can only be invoked on pointers.
iota比较特殊,可以被认为是一个可被编译器修改的常量,在每一个const关键字出现时被重置为0,然后在下一个const出现之前,每出现一次iota,其所代表的数字会自动增1。
这里[fn:8]讲的不错。
如下:
for {
select {
case xxx:
break
}
}
这里的break是select还是for? 答案是select
如果支持atomic的读写就用这个,因为这个更快一点
go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow go vet -vettool=$(which shadow)
golang gc 测试 go tool pprof -alloc_objects
go tool pprof -inuse_objects
go tool pprof bin/dupsdc
consistant hash Ketema algorithm
goreplay: https://github.com/buger/goreplay 用线上流量去压测 begeta: https://github.com/tsenart/vegeta http压测 gogo/protobuf: use in docker/etcd/k8s/tidb 压测数据 https://github.com/alecthomas/go_serialization_benchmarks runtime.MemoProfile() memory profile golang 的价值观: orthogonal composition of simple concepts with preference in concurrency go-kit/gokit: 微服务的基础框架 go tool compile -m 辅助分析对象的分配情况 “The go tool will ignore a directory named “testdata”, making it available to hold ancillary data needed by the tests.” go test -v -run=’^TestContainsAny$’ strings_test.go 之前许多时候对prefix相同的testcase没有办法,其实可以用正则。 云架构的核心就是解耦: 业务/运维解耦 系统/软件解耦 服务与服务之间解耦
// The number of elements copied by the copy function is the minimum of len(dst) and len(src). To make a full copy, you must allocate a big enough destination slice.
var src, dst []int
src = []int{1, 2, 3}
dst = make([]int, len(src))
n := copy(dst, src)
fmt.Println("dst:", dst, "(copied", n, "numbers)")
[fn:1] http://mmcloughlin.com/posts/your-pprof-is-showing
[fn:2] http://www.integralist.co.uk/posts/profiling-go/
[fn:3] https://rakyll.org/coredumps/
[fn:4] https://dave.cheney.net/high-performance-go-workshop/gophercon-2019.html
[fn:5] http://pro-tips-dot-com.tumblr.com/post/47677612115/kill-a-hung-go-process-and-print-stack-traces
[fn:6] https://dave.cheney.net/2017/04/30/if-a-map-isnt-a-reference-variable-what-is-it
[fn:7] https://i.stack.imgur.com/6S35J.png