Go 语言入门 -- 工程实践 | 青训营笔记

69 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

1. Goroutine

1.1 Why Goroutine

线程属于内核态,栈内核态;

协程是轻量级线程, 栈kB级 属于用户态

如下代码: 直接使用关键词 go 可以直接创建一个协程

func hello(i int) {
  defer fmt.Println("hello, ", i)
}
​
func main() {
  for i := 0; i < 5; i++ {
    //go hello(i)
    go func(j int) {
      hello(j)
    }(i)
  }
  time.Sleep(time.Second)
}
​

1.2 CSP -- goroutine communication

建议使用通信共享内存而不是通过共享内存实现通信,共享内存属于临界区,访问时需要加锁,会影响协程并发效率

image-20230130175457495.png

1.3 Channel

如下图, 无缓冲通道和有缓冲通道,原理类似于操作系统的单缓冲区和双缓冲区

语法: make(chan 元素类型, [缓冲大小])

image-20230130175714637.png

示例代码:

func CalSquare() {
  src := make(chan int)
  dest := make(chan int, 3)
  go func() {
    //defer 关键词的作用是 在同一作用域内代码执行完后执行该语句
    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)
  }
}

1.4 Lock 临界区

协程共享资源,互斥访问时,需要加锁

如图所示,如果对于共享资源 x 不加锁访问,下面例子会发生写后写的错误,导致最后结果与我们预期不相符。

image-20230130181109397.png

1.5 waitGroup

sync.WaitGroup 计数器包括如下三个操作函数

image-20230130181735394.png

如下示例中 time.Sleep() 函数可以由waitGroup 代替

image-20230130181604846.png

image-20230130181531053.png

2. 如何管理依赖库: GOPATH --> GO Vendor --> Go Model

2.1 GOPATH:

环境变量 GOPATH 是 go 项目的依赖库路径, 可通过 go env 查看或修改 $GOPATH 变量。

$GOPATH 下的三个目录作用如下所示:

image-20230130200457807.png

弊端:

image-20230130200929535.png

2.2 GO Vendor:

  • 项目目录下增加 vendor 文件, 所有依赖包副本形式放在 ProjectRoot/vendor

  • 依赖寻址方式: vendor => GOPATH

    每个项目引入一份依赖的副本(vendor),解决了多个项目中需要同一个package依赖的冲突问题。

image-20230130201244575.png

弊端:

  • 无法控制依赖的版本
  • 更新项目又可能出现依赖冲突,导致编译错误

image-20230130201607314.png

2.3 Go Module

目标 -- 定义版本规则和管理项目依赖关系

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

2.3.1 依赖管理三要素

  1. 配置文件,描述依赖 go.mod

  2. 中心仓库管理依赖库 Proxy -- 远程代理库

  3. 本地工具 go get/mod 指令

    image-20230130203202360.png

    • 主版本2+模块会在模块路径增加 /vN 后缀
    • 对于没有 go.mod 文件并且主版本2+的依赖,会 + incompatible

2.3.2 版本格式

image-20230130203359780.png

image-20230116213556603.png

2.3.3 依赖分发

image-20230130204436991.png

image-20230130204510547.png

2.3.4 工具

image-20230130204615070.png

image-20230130204635515.png

3.测试

  • 回归测试:抖音刷视频,点赞等测试
  • 集成测试: 自动化功能接口测试
  • 单元测试: 具体到每个函数模块

image-20230130204817209.png

3.1 单元测试

image-20230130205023156.png

assert & go test :

image-20230130205051606.png

image-20230130210042292.png

image-20230130205701601.png

编码原则:

编写函数应该尽量小,单一职责原则

image-20230130205810893.png

3.2 外部依赖测试

image-20230117101506855.png

3.2.1: 打桩 Mock

打桩后,使得函数不再被外部依赖影响

三方依赖: github.com/bouk/monkey

image-20230117104205384.png

image-20230130210601978.png

3.3 基准测试

go test -bench=.

测试性能,热点代码

image-20230130210650567.png