GO工程基础 | 青训营笔记

94 阅读2分钟
这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记

一、语言进阶

1.并发vs并行

并发:多线程程序在单核CPU上运行,时间片轮转控制线程运行时间
并行:多线程程序在多核CPU上运行
Go可以充分发挥并行优势,是为并发而生的

2.协程vs线程

线程:内核态,比较珍贵的资源,栈KB级别
协程:用户态,轻量级线程,栈MB级别

3.开启协程:

在调用函数时,前加go即可创建协程
func hello(name string){
    fmt.Println("hello "+name)
}
func main(){
    go hello("Mike")  //创建协程调用
    hello(“Mike”)  //主线程调用
}

4.协程通信——共享内存

提倡通过通信共享内存,而不是通过共享内存(需要加锁)实现通信
锁的定义如下:
//并发安全Lock
//定义内存加锁
var(
    x int64
    lock sync.Mutex
)
//锁的使用
func useClock(){
    lock.Lock()
    x += 1
    lock.Unlock()
}

5.协程通信——Channel

makechan 元素类型,[缓冲大小])
·无缓冲通道:make(chan int)
·有缓冲通道:makechan int,2)
示例如下:
func main(){
    src :=make(chan int)
    dest :=make(chan int,3)
    go func(){
        defer close(src)  //协程结束时关闭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{
        fmt.Printf("%v ",i)
    }
    
}

6.WaitGroup

由于协程运行时间不确定,暴力的使用sleep往往会增加时间开销
开启协程时+1
关闭协程时-1
主协程阻塞直到计数器为0
即等待所有并发任务完成。
函数作用
Add(delta int)计数器加delta
Done()计数器减一
Wait()阻塞直到计数器为0

二、Go依赖

  1. GOPATH时期
项目代码直接依赖src下的代码
go get 下载最新版本的包到src目录下
弊端:无法实现package的多版本控制
  • bin:项目编译产生的二进制文件
  • pkg:项目编译的中间产物,加速编译
  • src:项目源码

2.Go Vender时期

项目目录下增加vender文件,所有依赖包副本形式放在¥ProjectRoot/vender
依赖寻址方式:vender=>GOPATH
通过每个项目引入一个依赖的副本,解决了多个项目需要一个package的依赖冲突问题

无法控制依赖的版本
更新项目又可能出现依赖冲突导致编译出错
  • README.md
  • dao
  • handler
  • main.go
  • service
  • vendor

3.Go Module

通过go.mod文件管理依赖包版本
通过go get/go mod指令工具管理依赖包

4.依赖管理三要素

  • go.mod 配置文件,描述依赖
  • Proxy 中心仓库管理依赖库
  • go get/mod 本地工具

三、Go测试

从上到下覆盖率变大,但成本降低
  • 回归测试
  • 集成测试
  • 单元测试
规则:
  • 所有测试文件以 _test.go结尾
  • fun TestXxx(*testing.T)
  • 初始化逻辑放到TestMain中