这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
一、并发编程(Go可以充分发挥多核优势,高效运行)
1、并发VS并行
并发:多线程程序在一个核的cpu上运行
并行:多线程程序在多个核的cpu上运行
协程:用户态,轻量级线程,栈MB级别
线程:内核态,线程跑多个协程,栈KB级别
协程的实列
package main
import (
"fmt"
"time"
)
func hello(i int) {
println("hellp :" + fmt.Sprint(i))
}
func HelloGoRoutine() {
for i := 0; i < 5; i++ {
//协程
go func(j int) {
hello(j)
}(i)
}
time.Sleep(time.Second)
}
func main() {
HelloGoRoutine()
}
2、通信(提倡通过通信共享内存而不是通过共享内存而实现通信)
Channel
无缓冲通道 make(chan int)
有缓冲通道 make(chan int,2)
package main
import ()
func CalSquare() {
src := make(chan int)
dest := make(chan int, 2)
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)
}
}
func main() {
CalSquare()
}
3、并发安全Lock
计数器
Add(delta int) 计数器+delta
Done() 计数器-1
Wait() 阻塞直到计数器为0
开启协程+1;执行结束-1;主协程阻塞直到计数器为0
package main
import (
"fmt"
"sync"
)
func hello(i int) {
println("hellp :" + fmt.Sprint(i))
}
func ManyGoWait() {
var wg sync.WaitGroup
wg.Add(5)
for i := 0; i < 5; i++ {
go func(j int) {
defer wg.Done()
hello(j)
}(i)
}
wg.Wait()
}
func main() {
ManyGoWait()
}
二、依赖管理
1、GOPATH-弊端:无法实现package的多版本控制
2、Go Vendor 弊端:无法控制依赖的版本;更新项目又可能出现依赖冲突,导致编译错误
3、Go Module:
通过go.mod文件管理依赖包版本
通过go get/go mod指令工具管理依赖包
1、依赖管理三要素
1、配置文件,描述依赖 go.mod
2、中心仓库管理依赖库 Proxy
3、本地工具 go get/mod
indirect:间接依赖
incompatible:主版本2+模块会在模块路径增加/vN后缀;对于没有go.mod文件并且主版本2+的依赖,会加incompatible
2、依赖分发-回源
1、无法保证构建稳定性
2、无法保证依赖可用性
3、增加第三方压力
3、依赖分发-Proxy(稳定可靠)
4、go mod
init 初始化,创建go.mod文件
download 下载模块到本地缓存
tidy 增加需要的依赖,删除不需要的依赖
三、测试
从上到下覆盖率逐渐变大,成本却逐渐变小
回归测试
集成测试
单元测试
1、单元测试-规则
1、所有的测试文件以_test.go结尾
2、func TestXxx(*testing.T)
3、初始化逻辑放到TestMain中
四、项目实践
数据层:数据Model,外部数据的增删改查(Repository)
逻辑层:业务Entity,处理核心业务逻辑输出(Service)
视图层:试图view,处理和外部的交互逻辑(Controller)