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

40 阅读1分钟

2.1 Gorountine - 协程

2.1.1 并发与并行

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

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

Goroutine,协程(用户态,轻量级,栈KB级别),线程(内核态,跑多个协程,栈MB级别)

Go语言中开启协程案例:

package main
​
import (
  "fmt"
  "time"
)
​
func main() {
  for i := 0; i < 5; i++ {
    go func(j int) { // 使用go标识符创建协程
      fmt.Println(j)
    }(i)
  }
  time.Sleep(time.Second)
}

2.1.2 Channel通道

Go提倡通过 通信 共享内存

通过make可以创建无缓冲通道 make(chan int)或者有缓冲通道 make(chan int, 2)

下面创建一个A、B协程,前者负责生成数字到无缓冲通道中,后者负责从无缓冲通道取出数字,做平方后放入新的有缓冲通道中。

package main
​
func main() {
  src := make(chan int)
  dest := make(chan int, 3)
  // A协程
  go func() {
    defer close(src) // defer延迟执行,先defer的最后执行(栈结构)
    for i := 0; i < 10; i++ {
      src <- i
    }
  }()
​
  // B协程
  go func() {
    defer close(dest)
    for i := range src {
      dest <- i << 2 // i^2
    }
  }()
  for j := range dest {
    println(j)
  }
}

2.1.3 并发安全 Lock

如果共享内存,会存在并发安全问题。

用两个协程进行测试,分别执行加锁和不加锁的函数,对比其差异:

package main
​
import (
  "sync"
  "time"
)
​
var (
  x    int64
  lock sync.Mutex
)
​
func addWithLock() {
  for i := 0; i < 2000; i++ {
    lock.Lock()
    x += 1
    lock.Unlock()
  }
}
​
func add() {
  for i := 0; i < 2000; i++ {
    x += 1
  }
}
​
func main() {
  // 分别创建5个协程,分别+2000,总体+10000
  x = 0
  for i := 0; i < 5; i++ {
    go add()
  }
  time.Sleep(time.Second)
  println("NoLock: ", x) // 6225,执行结果不一致
​
  x = 0
  for i := 0; i < 5; i++ {
    go addWithLock()
  }
  time.Sleep(time.Second)
  println("WithLock: ", x) // 10000
}

2.1.4 WaitGroup

通过WaitGroup内置的计数器,可以实现阻塞等功能,如下所示:

package main
​
import (
  "fmt"
  "sync"
)
​
func main() {
  var wg sync.WaitGroup // 定义一个wg
  wg.Add(5)             // 设置阈值为5for i := 0; i < 5; i++ {
    go func(j int) { // 使用go标识符创建协程
      defer wg.Done() // Done一次计数器++
      fmt.Println(j)
    }(i)
  }
  wg.Wait() // 计数器到5继续执行这一步
}

2.2 依赖

2.2.1 管理

简单来说:站在巨人的肩膀上,因为工程项目不可能基于简单的编码搭建

演进历史:GOPATH -> Go Vendor -> Go Module,为了解决不同环境依赖版本不同的问题,以及控制依赖库的版本。

三要素:1. 配置文件,描述依赖(go.mod)2. 中心仓库管理依赖库(Proxy) 3. 本地工具(go get/mod)

依赖关系举例

2.2.2 分发

如果直接从GitHub等第三方构建项目,无法保证构建的稳定性、可用性(软件可以被增删改),且增加了第三方平台压力。

所以,使用Proxy保证稳定性。例如公共GOPROXY是一个集中式的存储库,全球各地的Golang开发者都可以使用它。它缓存了大量开源的Go模块,这些模块可以从第三方公开访问的VCS项目存储库中获得。

2.2.3 工具

go get

go mod init/download/tidy