Go的依赖管理 | 青训营笔记

40 阅读3分钟

线程&协程

首先来讲讲这两者的区别,后面的例子都会用线程来说明。

线程与协程的区别

  • 协程是用户态,更加轻量级,是轻量级线程。
  • 线程是内核态,比协程开销大。

并发并行

Go语言的依赖管理首先从多线程开始入手,学习视频带着我们认识了并发和并行,这两者都是多线程运行的方式,不同的是,并发是一个CPU轮流执行线程,那么当CPU在执行线程1时,线程2是被挂起的状态;而并行则是多个CPU执行线程,可以一起跑的状态。

  • 并发:

image.png

  • 并行:

image.png

几种状态

下面来复习一下线程的几个状态:

  • New(新创建)
  • Runnable(可运行)
  • Blocked(被阻塞)
  • Waiting(等待)
  • Timed Waiting(计时等待)
  • Terminated(被终止)

Blocked 与 Waiting 的区别

  • Blocked 是在等待其他线程释放锁。
  • Waiting 则是在等待某个条件,比如join的线程执行完毕,或者是被唤醒。

goroutine

Goroutine是Go语言的一种轻量级线程——协程,能够实现Go语言的多核执行,提升运行效率,减少开销。

func HelloPrint(j int){
    println("hello goroutine : " + fmt.Sprint(j))
}

func main(){
    for i := 0; i < 5; i++ {
         go func(j int){
             HelloPrint(j)
         }(i)
    }
    time.Sleep(time.Second)
}

CSP(Communicating Sequential Processes)

  1. 通过共享内存实现通信
  2. 通过通道实现通信
  • Channel
make (chan 元素类型,[缓冲大小])
make (chan int)
make (chan int, 2)

并发安全锁

有锁,能保证数值的一致性;无锁不能保证数值的一致性,数值有可能正确,也有可能错误。如何加锁:

var {
    x int
    lock sync.Mutex
}
lock.Lock
x += 1
lock.Unlock()

Waitgroup

Add(delta int): 计数器+delta

Done():计数器-1

Wait:阻塞直到计数器为0 先通过add方法,对计数器+5,然后开启协程,每个协程执行完后,通过Done对每个计数器-1,最后wait主协程阻塞,计数器为0时退出主协程。

func ManyGoWait() {
    var wg sync.WaitGroup
    wg.Add(5) //添加计数器的值
    for i := 0; i < 5; i++ {
        go func(j int) {
            defer wg.Done() // -1
            HelloPrint(j)
        }(i)
    }
    wg.Wait() //阻塞,直到为0
}

依赖管理

依赖管理演进:GOPATH --> Go Vendor --> Go module,前面两个都没能很好的控制依赖版本的问题,下面来看go module

Go Module

依赖管理三要素

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

版本

  1. 模块路径: 从模块路径可以看出哪里找到该模块,如果是github前缀则表示可以从GitHub中仓库找到,依赖包的源代码由github托管
依赖标识:[Module Path][Version]
  • 语义化版本

写法${MAJOR}.${MINOR}.${PACTH}, 不同的MAJOR版本表示不同的API,MINOR版本通常是新增的函数或者功能,向后兼容,PATCH版本一般是一些修复的bug

V1.3.0
  • 基于commit伪版本

写法vx.0.0-yyyymmddhhmmss-abcdefgh1234,时间戳(提交时间)+校验码(哈希码前12位)

v0.0.0-20220401081311-c38frfrbfnnb4

2. indirect:间接依赖 3. incompatible

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

对比Java中的maven

  • setting.xml
  • pom文件

go.mod & maven

Go 编译的时候,如果同一个程序的不同段的代码分别依赖不同版本的项目,会选择最低版本的编译

Java 会就近原则来选择,如下图,A会选择D1.0来依赖,因为路径更短;如果多个版本都有相同的最短路径,则会选择最先声明的版本进行上传

image.png

proxy

proxy是一个服务站点,里面存储了软件内容,可以从里面拉取依赖;go module通过GOPROXY环境变量控制如何使用Go Proxy;GOPROXY是一个站点URL列表,可以使用"direct"表示源站。

GOPROXY="https://proxy1.cn, https://proxy2.cn, direct" 先在proxy1下载依赖,没有再向proxy2下载,如果还没有再去源站点下载依赖,缓存在proxy站点中

go get工具

go get example.org/pkg
@update 默认
@none 删除依赖
@v1.1.2 tag版本,语义版本
@2233df4 特定的commit
@master 分支最新的commit

go mod工具

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

!!!go.mod文件和go mod注意区分