day02-Go工程实践与依赖管理, 测试 | 青训营

55 阅读2分钟

day02-Go工程实践与依赖管理, 测试

Ⅰ.并发

  1. Goroutine 通过关键词go创建协程
    go func(j int){
        // do something
    }(args)
  1. CSP 线程共享内存 通信共享内存与共享内存实现通信如下图所示,Go提倡通过通信共享内存。临界区需要加锁保证并发安全。

CSP.png

  1. Channel Channel(通道)包括无缓冲通道有缓冲通道,通道的运作类似消息队列,遵循先进先出,保证消息的顺序,保证并发安全。当通道满的时候,会阻塞消息的发送直到某个Gorountine把消息取走。

Channel.png 声明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)
        }
    }

  1. 并发安全Lock 协程通过共享内存来实现通信需要通过加锁来保证消息顺序的正确性,安全的读写操作
var(
    x int64
    lock sync.Mutex
)
func addWithLock(){
    for i := 0; i < 2000; i++{
        lock.Lock() // 加锁
        x += 1
        lock.Unlock() //解锁
    }
}
  1. 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() // 阻塞

Ⅱ. 依赖管理

  1. Go依赖管理的迭代

    GOPATH -> Go Vendor -> Go Module

    • 不同环境(项目)依赖的版本不同

    • 控制依赖库的版本

    1. 环境变量$GOPATH

      项目代码直接依赖src下的代码,go get 下载最新版本的包到src目录下,弊端无法实现package的多版本控制

    2. Go vendor

      项目目录下增加vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor,寻址方式为vendor => GOPATH, 解决了多个项目需要同一个package的问题
      弊端:无法控制依赖的版本与更新项目时可能出现依赖冲突,导致编译出错

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

  2. Go proxy
    环境变量GOPROXY = "https://proxy1.cn, direct" Proxy1 => Direct

  3. 依赖工具
    go get example.org/pkg

    • @update 默认
    • @none 清除依赖
    • @x.x.x tag版本,语义版本
    • @23dfdd5 特定的commit
    • @master 分支的最新commit

    go mod init

    • init 初始化,创建go.mod
    • download 下载模块到本地缓存
    • tidy 增加需要的依赖,删除一需要的依赖

测试

  1. 单元测试
  • 所有测试文件以_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