Go 语言进阶
并发 vs 并行
协程 - 用户态、轻量级线程,栈 KB 级别
线程 - 内核态、线程跑多协程、栈 MB 级别
CSP
提倡通过通信共享内存(通道)而非直接共享内存(临界区)
Channel
make(chan <type>, [size])
无缓冲通道
有缓冲通道
src := make(chan int)
dest := make(chan int, 3)
go func() {
defer close(src)
for i := 0; i < 10; i++ {
src <- i
}
}()
go func() {
defer close(dest)
for i := range src {
dest <- i * i
}
}()
for i := range dest {
println(i)
}
并发 Lock
lock.Lock()
lock.Unlock()
j := 0
var lock sync.Mutex
for i := 0; i < 5; i++ {
go func() {
for i := 0; i < 1000; i++ {
lock.Lock()
j++
lock.Unlock()
}
}()
}
time.Sleep(time.Second)
println("add with lock", j)
依赖管理
Go依赖演进
GOPATH
项目代码直接依赖src下代码
Go Vendor
项目目录内实现vendor目录
Go Module
通过go.mod管理依赖包
依赖管理要素
配置文件
go.mod
中心仓库
proxy
本地工具
go get & go mod
语义化版本
${MAJOR}.${MINOR}.${PATCH}
commit版本
vx.0.0-yyyymmddhhmmss-abcdefgh1234
依赖配置
module XXX
go X.X
require (
example/lib v1.1.1
)
依赖分发-回源
依赖分发-变量 GOPROXY
从proxy直至源站获取依赖
测试
单元测试
- 规则
测试文件以_test.go结尾
测试函数以Test开头
初始化逻辑置于TestMain函数内
- 示例
package Go
import (
"github.com/stretchr/testify/assert"
"os"
"testing"
)
func TestDemo(t *testing.T) {
output := 1 + 1
expectOutput := 2
assert.Equal(t, output, expectOutput)
}
func TestMain(m *testing.M) {
code := m.Run()
os.Exit(code)
}
- 运行
go test [flags] [packages]
- assert
assert.Equal(t, output, expectOutput)
参见 github.com/stretchr/testify/assert
- 覆盖率
一般覆盖率在50%-60%左右,较高覆盖率80%+
测试分支相互独立,全面覆盖
测试单元粒度足够小,函数单一职责
import (
"github.com/stretchr/testify/assert"
"os"
"testing"
)
func TestDemo(t *testing.T) {
output := 1 + 1
expectOutput := 2
assert.Equal(t, output, expectOutput)
}
func TestMain(m *testing.M) {
code := m.Run()
os.Exit(code)
}
Mock测试
- 依赖
File、DB、Cache
外部依赖 - 稳定&幂等
- 文件
文件使用
- mock
为函数or方法打桩
patch -> test -> unpatch
基准测试
测试代码的性能