使用golang
Go
https://storage.googleapis.com/golang/go1.13.linux-amd64.tar.gz
https://storage.googleapis.com/golang/go1.13.windows-amd64.zip
https://storage.googleapis.com/golang/go1.13.darwin-amd64.tar.gz
所有发布的版本
https://storage.googleapis.com/golang/
国内可访问地址
https://dl.google.com/go/go1.13.windows-amd64.msi
https://dl.google.com/go/go1.13.darwin-amd64.pkg
https://dl.google.com/go/go1.13.linux-amd64.tar.gz
https://dl.google.com/go/go1.13.src.tar.gz
https://dl.google.com/go/go1.13.darwin-amd64.tar.gz
https://dl.google.com/go/go1.13.linux-386.tar.gz
https://dl.google.com/go/go1.13.linux-armv6l.tar.gz
https://dl.google.com/go/go1.13.windows-386.zip
https://dl.google.com/go/go1.13.windows-386.msi
https://dl.google.com/go/go1.13.windows-amd64.zip
https://dl.google.com/go/go1.13.freebsd-386.tar.gz
https://dl.google.com/go/go1.13.freebsd-amd64.tar.gz
https://dl.google.com/go/go1.13.linux-arm64.tar.gz
https://dl.google.com/go/go1.13.linux-ppc64le.tar.gz
https://dl.google.com/go/go1.13.linux-s390x.tar.gz
golang c lib
go 编译.a用的go build -buildmode=c-archive ,c程序用的gcc
Creating Statically Linked Executables In Go
https://joeshaw.org/smaller-docker-containers-for-go-apps/
https://github.com/gliderlabs/docker-alpine
CGO_ENABLED=0 go build -a -ldflags "-s" tiny.go
The CGO_ENABLED environment variable tells Go to use the go compiler rather than the cgo compiler. The -a flag tells Go to rebuild all dependencies. Otherwise you still end up with dynamically linked dependencies. And finally the -ldflags ‘-s’ flag is a nice extra. It reduces the file size of the resulting executable by roughly 50%. You can also do this without the go compiler. The size reduction is a result from removing debug information.
GO原生支持跨平台编译,可以直接在Mac上生成Linux可执行程序,和Windows上的exe程序
生成Linux上64位:CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -ldflags "-s -w" tiny.go
生成Windows上64位:CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -a -ldflags "-s -w" tiny.go
编译32位程序,可以改为GOARCH=386
Linux arm 编译 CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -a -ldflags "-s -w" tiny.go
CGO_ENABLED=0 GOARM=7 GOOS=linux GOARCH=arm go build -a -ldflags "-s -w" tiny.go
-a 参数指明所有的引用也进行编译打包到可执行程序,可以完成静态编译.
ldflags:
-s
指明需要经过strip
,去除调试信息,使生成的可执行文件更小.-w
也能减少文件的大小
参数含义见 https://golang.org/cmd/link/
使编译后的文件更小的办法
-
使用
go build -ldflags "-s -w"
来编译文件.此时生成的文件,去除了调试信息,文件体积尽量缩减. -
Go 1.6及以后版本直接使用
upx
进一步减少体积,1.6之前版本还需要使用goupx
upx
使用见 https://upx.github.io/
mac用户可以使用brew install upx
安装
设置GOPATH环境变量
export GOPATH=/home/apple/mygo
GOPATH允许多个目录,当有多个目录时,请注意分隔符,多个目录的时候Windows是分号,Linux系统是冒号,当有多个GOPATH时,默认会将go get的内容放在第一个目录下
$GOPATH 目录约定有三个子目录:
- src 存放源代码(比如:.go .c .h .s等)
- pkg 编译后生成的文件(比如:.a)
- bin 编译后生成的可执行文件(为了方便,可以把此目录加入到 $PATH 变量中)
golang 程序性能分析
go tool pprof http://172.168.1.5:6002/debug/pprof/heap
go tool pprof http://172.168.1.5:6002/debug/pprof/goroutine
go tool pprof http://172.168.1.5:6002/debug/pprof/profile
查看内存分析
查看或生成性能图表需要安装graphviz
brew install graphviz
或者 yum -y install graphviz
go tool pprof main profile_file
top10
查看最消耗资源的调用
web
top命令可以看最耗时的function。它的输出格式各字段的含义依次是:
采样点落在该函数中的次数
采样点落在该函数中的百分比
上一项的累积百分比
采样点落在该函数,以及被它调用的函数中的总次数
采样点落在该函数,以及被它调用的函数中的总次数百分比
函数名
HeapAlloc: essentially what the profiler is giving you (active heap memory) Alloc: similar to HeapAlloc, but for all go managed memory Sys: the total amount of memory (address space) requested from the OS
设置变量 GODEBUG="gctrace=1"
可以监控gc执行时在控制台打印出信息.
import _ "net/http/pprof"
go tool pprof http://localhost:6060/debug/pprof/heap
go get -u -v github.com/davecheney/gcvis
https://dave.cheney.net/2014/07/11/visualising-the-go-garbage-collector
go build -gcflags=-m fastload/fastload.go
编译任何一个文件,查看他的逃逸分析,和内联函数的优化
逃逸分析是在编译时而不是运行的时候做的。
无论垃圾回收机制多么高效,栈的分配总是比堆的分配要快。
在栈上存储的变量不需要特别的分配和释放操作,栈上分配的会在函数返回时释放内存,不需要垃圾回收机制.
在堆(heap)上分配内存是有代价的。每次垃圾回收机制触发都会消耗一定的CPU。除非内存都被释放了,这些开销是不可避免的。
golang 性能火焰图
安装go-torch
go get -v github.com/uber/go-torch
wget https://raw.githubusercontent.com/brendangregg/FlameGraph/master/flamegraph.pl
在终端输入 flamegraph.pl -h 是否安装FlameGraph成功
启用待调优的程序
import _ "net/http/pprof"
go run main.go
使用测压工具或手动模拟测试
go-torch -u http://localhost:6060 -t 30
采样30秒,生成火焰图.会自动生成svg文件,我们用浏览器打开svg文件就可以查看分析了.
也可以执行 go tool pprof --seconds 25 http://localhost:6060/debug/pprof/profile
使用 golang自带的工具采样,然后使用web
命令生成svg文件并查看.
golang 优化
- 字符串与数组相互转化时发生复制
- array 以 pass-by-value 方式传递,函数调用会发生复制,但不是总要避免这种复制,对于一些短小的对象,复制成本远小于在堆上分配和回收操作
- defer 滥用引起的问题
- 避免频繁穿件go
https://segmentfault.com/u/qyuhen/articles
golang 指针
用不用指针取决2个方面
1, 大小(go是传值的),数据太大, 压栈浪费内存 2, 你有还函数内部修改,并保证外部可见的需求
go 不区分堆和栈,或者说,go自己处理这些问题,和用户无关,用户也不可知
什么情况下不使用指针
- 数据太小,小于指针大小,或者你可以容忍传值开销
- 明确需求传值,通常希望修改对外部不可见情况
- 类型内部是通过指针引用数据的(例如map,slice) 或者数据本身就是指针
- 如果不理解或不清楚上述三点是否适用,一律适用指针
Go语言的指针,基本上只用于区分 byref 和 byval 语义
运算符就是简单的 & 和 * 一个取地址、一个解析地址。
传值与传指针 当我们传一个参数值到被调用函数里面时,实际上是传了这个值的一份copy,当在被调用函数中修改参数值的时候,调用函数中相应实参不会发生任何变化,因为数值变化只作用在copy上。
传指针比较轻量级 (8bytes),只是传内存地址,我们可以用指针传递体积大的结构体。如果用参数值传递的话, 在每次copy上面就会花费相对较多的系统开销(内存和时间)。所以当你要传递大的结构体的时候,用指针是一个明智的选择。
Go语言中string,slice,map这三种类型的实现机制类似指针,所以可以直接传递,而不用取地址后传递指针。(注:若函数需改变slice的长度,则仍需要取地址传递指针)
调试
https://github.com/derekparker/delve
dvl attach pid
golang bin
一些常用的golang 可执行程序
# google drive
go get -u -v 'github.com/prasmussen/gdrive'
# 16进制编辑器
go get -u -v github.com/itchyny/bed/cmd/bed
# 压力测试工具
go get -u -v github.com/tsenart/vegeta
# ossutil
go get -u -v github.com/aliyun/ossutil
其他语言里的协程
https://owent.net/2018/1806.html
sync.Map并不适合同时存在大量读写的场景,大量的写会导致read map读取不到数据从而加锁进行进一步读取,同时dirty map不断升级为read map。 从而导致整体性能较低,特别是针对cache场景.针对append-only以及大量读,少量写场景使用sync.Map则相对比较合适。
sync.Map没有提供获取元素个数的Len()方法,不过可以通过Range()实现。