工程实践 | 青训营笔记

126 阅读3分钟

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

语言进阶

Golang的并发编程的讲解。

  • 并发:多线程程序在一个核的cpu上运行

  • 并行:多线程程序在多个核的cpu上运行

  • 线程:内核态,线程跑多个协程,栈MB级别

  • 协程:用户态,轻量级线程,栈KB级别

协程之间通过通信共享内存 -- 使用channel(通道)

channel

make(chan 元素类型 [缓冲大小])
//有缓冲通道
make(chan int, 2)
//无缓冲通道 同步通道
make(chan int)

简单的channel通信样例

func CalSquare(){
    src := make(chan int)
    dest := make(chan int, 2)
    go func() {
        defer close(src) //函数最后结束时关闭channel
        for i := 0; i < 10; i ++ {
            src <- i //将i放入管道,由于src无缓冲放入后在被接收前,协程将被堵塞
        }
    }()
    
    go func() {
        defer close(dest)
        for i := range src {
            dest <- i * i //由于dest存在缓冲,当dest中缓冲未满的状态时,可以连续接收src传递的数据
        }
    }()
    
    for i := range dest{
        //可能消费速度比生产速度慢,所以使用了有缓冲的chan
        println(i)
    }
    
}

并发安全Lock

var (
    x int64
    lock sync.Mutex
)

func addWithLock() {
    for i := 0; i < 2000; i ++ {
        lock.Lock()
        x += i
        lock.UnLock()
    }
}

func addWithoutLock() {
    for i:= 0; i < 2000; i ++ {
        x += 1
    }
}

WaitGrouo

Add(delta int) 计算器+delta Done() 计算器-1 Wait() 阻塞直到计数器为0

计数器

开启协程+1 执行结束-1 主协程阻塞到计数器为0

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()
}

依赖管理

  • 工程项目不可能基于标准课0~1编码搭建
  • 管理依赖库

GOPATH -> Go Vender -> GoModule

GOPATH工作模式的弊端

  • 没有版本控制概念
  • 无法同步一次第三方版本号
  • 无法指定当前项目引用的第三方版本号 我们一般使用GoModule

(1) go mod命令

命令作用
go mod init生成 go.mod 文件
go mod download下载 go.mod 文件中指明的所有依赖
go mod tidy整理现有的依赖
go mod graph查看现有的依赖结构
go mod edit编辑 go.mod 文件
go mod vendor导出项目所有的依赖到vendor目录
go mod verify校验一个模块是否被篡改过
go mod why查看为什么需要依赖某模块

GOPROXY

这个环境变量主要是用于设置 Go 模块代理(Go module proxy),其作用是用于使 Go 在后续拉取模块版本时直接通过镜像站点来快速拉取。

GOPROXY 的默认值是:https://proxy.golang.org,direct

proxy.golang.org国内访问不了,需要设置国内的代理.

如:

$ go env -w GOPROXY=https://proxy.golang.com.cn,direct

GOPROXY 的值是一个以英文逗号 “,” 分割的 Go 模块代理列表,允许设置多个模块代理,假设你不想使用,也可以将其设置为 “off” ,这将会禁止 Go 在后续操作中使用任何 Go 模块代理。

如:

$ go env -w GOPROXY=https://goproxy.cn,https://mirrors.aliyun.com/goproxy/,direct

direct

而在刚刚设置的值中,我们可以发现值列表中有 “direct” 标识,它又有什么作用呢?

实际上 “direct” 是一个特殊指示符,用于指示 Go 回源到模块版本的源地址去抓取(比如 GitHub 等),场景如下:当值列表中上一个 Go 模块代理返回 404 或 410 错误时,Go 自动尝试列表中的下一个,遇见 “direct” 时回源,也就是回到源地址去抓取,而遇见 EOF 时终止并抛出类似 “invalid version: unknown revision...” 的错误。

使用go get下载包

测试

单元测试

  • 所有测试文件以_test.go结尾
  • func TestXxx(*testing.T)
  • 初始化逻辑放在TestMain中

覆盖率

如何衡量代码是否经过了足够的测试 如何评价项目的测试水准 如何评估项目是否达到了高水准测等级

  • 一般覆盖率:50%~60% 较高覆盖率80%
  • 测试分支相互独立
  • 测试单元粒度足够小,函数单一职责

依赖

外部依赖 => 稳定&幂等

Mock测试

monkey: github.com/bouk/monkey

快速Mock函数

  • 为一个函数打桩
  • 为一个方法打桩

基准测试

  • 优化代码
  • 内置的测试框架提供了基准测试的能力

项目实践