苏苏的博客

简约至极

使用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/

使编译后的文件更小的办法

  1. 使用go build -ldflags "-s -w"来编译文件.此时生成的文件,去除了调试信息,文件体积尽量缩减.

  2. 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内存

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 优化

  1. 字符串与数组相互转化时发生复制
  2. array 以 pass-by-value 方式传递,函数调用会发生复制,但不是总要避免这种复制,对于一些短小的对象,复制成本远小于在堆上分配和回收操作
  3. defer 滥用引起的问题
  4. 避免频繁穿件go

https://segmentfault.com/u/qyuhen/articles

golang 指针

用不用指针取决2个方面

1, 大小(go是传值的),数据太大, 压栈浪费内存 2, 你有还函数内部修改,并保证外部可见的需求

go 不区分堆和栈,或者说,go自己处理这些问题,和用户无关,用户也不可知

什么情况下不使用指针

  1. 数据太小,小于指针大小,或者你可以容忍传值开销
  2. 明确需求传值,通常希望修改对外部不可见情况
  3. 类型内部是通过指针引用数据的(例如map,slice) 或者数据本身就是指针
  4. 如果不理解或不清楚上述三点是否适用,一律适用指针

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()实现。