day02-Go工程实践与依赖管理, 测试
Ⅰ.并发
- Goroutine
通过关键词
go创建协程
go func(j int){
// do something
}(args)
- CSP 线程共享内存
通信共享内存与共享内存实现通信如下图所示,
Go提倡通过通信共享内存。临界区需要加锁保证并发安全。
- Channel Channel(通道)包括无缓冲通道与有缓冲通道,通道的运作类似消息队列,遵循先进先出,保证消息的顺序,保证并发安全。当通道满的时候,会阻塞消息的发送直到某个Gorountine把消息取走。
声明Channel的方式:
make(chan 元素类型, [缓冲大小])
make(chan int) //int类型的无缓冲通道
make(chan int, 2) //int类型的有缓冲通道
//example
func CalSquare(){
src := make(chan int)
dest := make(chan int, 3)
go func(){
defer close(src)
for i := 0; i < 10; i++{
src <- i // 将i放入src通道中
}
}()
go func(){
defer close(dest)
for i := range src{
dest <- i * i //在src中依次取出i求平方放入dest中
}
}()
for i := range dest{
// do something
println(i)
}
}
- 并发安全Lock 协程通过共享内存来实现通信需要通过加锁来保证消息顺序的正确性,安全的读写操作
var(
x int64
lock sync.Mutex
)
func addWithLock(){
for i := 0; i < 2000; i++{
lock.Lock() // 加锁
x += 1
lock.Unlock() //解锁
}
}
- WaitGroup
waitgroup是一个计数器,包含
Add(delta int),Wait(),Done()方法,开启协程+1,执行结束-1;主协程阻塞直到计数器为0
var wg sync.WaitGroup
wg.Add(5)
for i := 0; i < 5; i++ {
go func(j int){
defer wg.Done() //计数器-1
}(i)
}
wg.Wait() // 阻塞
Ⅱ. 依赖管理
-
Go依赖管理的迭代
GOPATH -> Go Vendor -> Go Module
-
不同环境(项目)依赖的版本不同
-
控制依赖库的版本
-
环境变量$GOPATH
项目代码直接依赖src下的代码,go get 下载最新版本的包到src目录下,弊端无法实现package的多版本控制
-
Go vendor
项目目录下增加vendor文件,所有依赖包副本形式放在
$ProjectRoot/vendor,寻址方式为vendor => GOPATH, 解决了多个项目需要同一个package的问题
弊端:无法控制依赖的版本与更新项目时可能出现依赖冲突,导致编译出错 -
Go Module 通过
go.mod文件管理依赖包版本,通过go get/go mod指令工具管理依赖包
-
-
Go proxy
环境变量GOPROXY = "https://proxy1.cn, direct"Proxy1 => Direct -
依赖工具
go get example.org/pkg- @update 默认
- @none 清除依赖
- @x.x.x tag版本,语义版本
- @23dfdd5 特定的commit
- @master 分支的最新commit
go mod init- init 初始化,创建go.mod
- download 下载模块到本地缓存
- tidy 增加需要的依赖,删除一需要的依赖
测试
- 单元测试
- 所有测试文件以
_test.go结尾 - 函数命名为
func TestXxx(t *testing.T) - 初始化逻辑放到
TestMain函数中
func TestMain(m *testing.M){
//数据装载,配置初始化等
code := m.Run()
//释放资源等
os.Exit(code)
}
运行: go test [flags][packages]
通过assert.Equal(*testing.T, expectOutput, output)来判断 包(github.com/stretchr/testify/assert)
覆盖率:一般为50% ~ 60%
go test xxx_test.go xxx.go --cover