Go的依赖管理与工程实践|青训营笔记

81 阅读3分钟

Go的依赖管理与工程实践|青训营笔记

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

在后面会依次倒叙回顾之前的学习课程,便于复习~

一、课程重点内容

  • Go的并发编程
  • 依赖管理
  • 单元测试

下面是对课程重点内容的思考与总结,有问题或者错误,可以批评指正呐~

二、Go的并发编程

我们知道在go语言里面启动协程是使用go指令,这样会使得程序运行另一个子程序,也就是实现了并发,这里线程与协程又是什么区别呢?

  • 协程与线程、进程

    首先从一张图片看出线程、协程、进程之间的关系:

    image-20230208210205786.png

    • 协程(coroutine)是一种程序组件,是一种比线程更加轻量级的存在。正如一个进程可以有多个线程,一个线程可以有多个协程。
    • 在任务调度上,协程是弱于线程的。但是在资源消耗上,协程则是极低的。一个线程的内存在 MB 级别,而协程只需要 KB 级别。而且线程的调度需要内核态与用户的频繁切入切出,资源消耗也不小。
  • 通道Channel

    • 定义:通道是用来传递数据的一个数据结构,可以用于两个goroutine之间,通过传递一个指定类型的值来同步运行和通讯。这有点类似于条件量。
    • 操作符:<-,用于指定通道的方向,实现发送or接收,如果未指定方向,则默认双向
    • 使用技巧:通道在使用前必须先创建;
  • 并发控制

    • Mutex互斥锁:通过争夺锁,来使得两个或多个协程之间互相等待,而不是顺次执行,这样会导致性能急剧下降,由于激烈的争夺锁。

    • WaitGroup:使用方法如下

       func main() {
        var waitGroup sync.WaitGroup
       ​
        start := time.Now()
        waitGroup.Add(5)
        for i := 0; i < 5; i++ {
         go func() {
          defer waitGroup.Done()
          time.Sleep(time.Second)
          fmt.Println("done")
         }()
        }
       ​
        waitGroup.Wait()
        fmt.Println(time.Now().Sub(start).Seconds())
       }
       ​
       /*
       done
       done
       done
       done
       done
       1.000306089
       */
      

      使用 Add(5) 表示我们有 5个 子任务,然后起了 5个 协程去完成任务,主协程使用 Wait() 方法等待 子协程执行完毕,输出一共等待的时间。

      WaitGroup 一共有三个方法:

       (wg *WaitGroup) Add(delta int)
       (wg *WaitGroup) Done()
       (wg *WaitGroup) Wait()
      
      • Add 方法用于设置 WaitGroup 的计数值,可以理解为子任务的数量
      • Done 方法用于将 WaitGroup 的计数值减一,可以理解为完成一个子任务
      • Wait 方法用于阻塞调用者,直到 WaitGroup 的计数值为0,即所有子任务都完成

三、依赖管理

  • GOPATH

    它是一个环境变量,主要由三个部分组成:

    • bin:项目编译的二进制文件
    • pkg:项目编译的中间产物,加速编译
    • src:项目源码,项目代码直接依赖src下的代码go get下载最新版本的包到src目录下

    存在的弊端:无法实现package的多版本控制

  • Go Vender

    • 位置:项目目录下增加vender文件,所有依赖包副本形式放在$ProjectRoot/vender
    • 依赖寻址方式:vender -> GOPATH
    • 通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package依赖的冲突问题。
    • 存在的弊端:更新项目的时候可能导致编译错误的冲突;无法控制依赖的版本。
  • Go Module

    • 通过mod文件进行依赖管理,在发生依赖冲突时,只需要执行go mod tidy即可,下载包使用go get -u packagename

      image.png

四、单元测试

在开发文件夹下面建立一个XXX_test.go的文件,用于测试开发功能,在内部将函数名命名为TestXXXgo会自动识别该函数。

 package greetings
 ​
 import (
     "regexp"
     "testing"
 ​
     "github.com/stretchr/testify/assert"
 )
 ​
 // TestHelloName calls greetings.Hello with a name, checking
 // for a valid return value.
 func TestHelloName(t *testing.T) {
     name := "Gladys"
     want := regexp.MustCompile(`\b` + name + `\b`)
     msg, err := Hello("Gladys")
     if !want.MatchString(msg) || err != nil {
         t.Fatalf(`Hello("Gladys") = %q, %v, want match for %#q, nil`, msg, err, want)
     }
 }
 ​
 // TestHelloEmpty calls greetings.Hello with an empty string,
 // checking for an error.
 func TestHelloEmpty(t *testing.T) {
     msg, err := Hello("")
     assert.NotEqual(t, msg, " ", "msg error")
     assert.NotEqual(t, err, nil, "err failed")
 ​
 }

image-20230208212710552.png

通过点击run test就能实现测功能,这里的话强烈推荐搭配assert,这样的话大大提高测试开发速度。

image-20230208213030927.png

五、课程总结

通过学习并发编程,让自己对于并发控制的概念更加深入,其次是依赖管理,现在的版本红利使得管理依赖非常简单,最后是单元测试,这是一个项目成功的关键,一个好的项目就是在不断地测试下走向成功的。