这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
语言进阶
Goroutine
协程
func hello(j int){
fmt.Println(j)
}
func HelloGoroutine(){
for i:=0;i<5;i++{
go func(j int){
hello(j)
}(j)
}
time.Sleep(time.Second) //防止携程晚于主线程退出
}
Channel
- 通过通信共享内存,而不是通过共享内存而实现通信(互斥量加锁)
即channel
-
Channel
make(chan 元素类型,[缓冲大小])- 无缓冲通道
make(chan int)同步通道,有阻塞 - 有缓冲通道
make(chan int,2)满了阻塞
//通信实现共享内存
/*
* A子携程发送0-8数字
* B子携程计算输入数字的平方
* 主协程输出最后的平方数字
*/
func CalSquar(){
//不带缓冲和带缓冲
src := make(chan int)
dest := make(chan int,3)
go func(){
defer close(src)
for i:=0;i<10;i++{ // A
src <- i
}
}()
go func(){
defer close(dest)
for i := range src{ //B
dest <- i*i
}
}()
for i := range dest{
//
println(i)
}
}
并发安全Sync
//锁
var lock sync.Mutex
lock.Lock()
lock.Unlock()
WaitGroup协程同步Sync
- WaitGroup包
Add(delta int) //计数器+delta
Done() //计数器-1
Wait() //阻塞直到计数器为0
func hello(j int){
fmt.Println(j)
}
func HelloGoroutine(){
var wg sync.WaitGroup
wg.Add(5) //设置协程个数
for i:=0;i<5;i++{
go func(j int){
wg.Done() //-1
hello(j)
}(j)
}
wg.Wait() //防止携程晚于主线程退出
}
TODO :测试如果线程早于协程(sleep)退出会发生什么
依赖管理
GOPATH
-
go的工作区
目录结构(go的库位置)/home/ubuntu/go
bin pkg src //源码存在的位置 -
缺点:因为是GO的环境变量,所以所有的项目都使用同一个PATH,依赖同一个版本的Go包,无法实现不同项目的版本管理
Go Vendor
- 项目目录下增加vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor
依赖寻址方式:vendor=>GOPATH
- 无法实现一个项目不同的模块依赖不同的版本
Go Module
- 通过
go.mod文件管理 - 通过
go get/go mod指令工具管理依赖
- 依赖管理三要素
- 配置文件,描述依赖 go.mod
- 中心仓库管理依赖库 Proxy
- 本地工具
go get/go mod
-
go.mod
- 对于go代码中的
import,实际上需要的是module模块,即package的路径,因此尽量让文件夹名字与package name一致 ,如果不一致,go.mod中的module ...和.go中import ...中对应都填路径(路径要求以域名的形式给出),.go中调用时用package name
- 对于go代码中的
//依赖管理基本单元
module github.com/Moonlight-Zhao/go-project-example
go 1.16
require (//依赖
github.com/gin-contrib/sse v0.1.0 // indirect 间接依赖
github.com/gin-gonic/gin v1.3.0 // indirect
github.com/go-playground/validator/v10 v10.10.0 // indirect
github.com/goccy/go-json v0.9.6 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/stretchr/testify v1.7.1 // indirect
github.com/ugorji/go v1.2.7 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/gin-gonic/gin.v1 v1.3.0
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gorm.io/driver/mysql v1.3.3
gorm.io/gorm v1.23.4
)
- 依赖版本
语义化版本
V1.3.0 git tag
基于commit的伪版本
vx.0.0-yyyymmddhhmmss-abcdadfa1234
依赖分发
- 直接依赖第三方线上库,会因为网络和线上资源问题出现各种问题
使用Proxy
GOPROXY="https://.....",从前往后代理
go get
go get example.org/pkg ...
+
@update 默认
@none 删除依赖
@v1.1.2 tag版本,语义版本
@23434f 特定提交
@master 分支最新commit
go mod
go mod ...
+
init 初始化,构建go.mod文件
download 下载模块到本地缓存
tidy 增加所需要的依赖,删除不需要的依赖
测试
单元测试
-
所有的测试文件以
_test.go结尾 -
测试函数要求
func TestXxx(t* testing.T) -
初始化逻辑放到
TestMain中func TestMain(m *testing.M){ //测试前:数据装载、配置初始化等 //跑当前package下的所有单元测试(所有的_test.go文件) code := m.Run() //测试后:资源释放 //退出 os.Exit(code) } -
例子
func HelloTom() string{
return "Jerry"
}
---------
func TestHelloTom(t *testing.T){
output := HelloTom()
expectOutput := "Tom"
if output != expectOutput{
t.Errorf("Excepted %s, but %s\n",expectOutput,output)
}
}
------测试运行
go test [flags] [packages]
go test judgment_test.go judgement.go [--cover]
- assert 包
import "github.com/stretchr/testify/assert"
mock测试
monkey : https://github.com/bouk/monkey
快速Mock函数
-
为一个函数打桩(将一个函数替换为另外一个函数,用于测试)
func TestProcessFirstLineWithMock(t *testing.T){ monkey.Patch(ReadFirstLine,func()string{ return "line110" })//将第一个函数进行替换为第二个参数 defer monkey.Unpatch(ReadFirstLine) //取消打桩 line := ProcessFirstLine() assert.Equal(t,"line000",line) }
基准测试
- 用于性能分析
func BenchmarkSelect(b *testing.B){
b.ResetTimer()
for i:=0;i<b.N;i++{
Select() //被测试的函数
}
}
func BenchmarkParallel(b *testing.B){
b.ResetTimer()
b.RunParallel(func(pb *testing.PB){
for pb.Next(){
Select()
}
})
}
-------
go test -bench=.