GO语言进阶 | 豆包MarsCode AI刷题

84 阅读4分钟

GO进阶

  1. 语言进阶(并发视角看Go高性能本质)
  2. 依赖管理(了解Go语言依赖管理演进度)
  3. 测试(单元测试)
  4. 项目实战

01 并发和并行

1.1 Goroutine

  • 协程 ( 用户态)轻量线程 kb
  • 线程 内核态 mb
func hello(i int){
  println("hello goroutine : " + fmt.Sprint(i))
}
​
func HelloGoRoutine(){
  for i := 0; i < 5; i++{
    go func(j int){
      hello(j)
    }(i) // 创建了一个匿名函数,并用 go 关键字启动该匿名函数作为一个 goroutine 运行。(i)表示 i 作为了参数传给了匿名函数
  }
  time.Sleep(time.Second)
}

1.2 协程通信(CSP模型)

协程通信的 CSP(Communicating Sequential Processes)模型是一种并发编程模型,主要用于描述和分析多任务、多个协程之间的通信与同步。CSP模型的核心思想是 进程之间通过通信进行交互,而非共享内存。每个进程都有自己的独立状态,进程间通过消息传递(通常是通过管道或者队列)进行协作。

1.3 Channel

  • 无缓冲通道
  • 有缓冲通道

生产消费模型

并发安全

但是go也保存了共享内存来通信的方式

1.4 并发安全 Lock

image.png

undefined 问题

1.5 WaitGroup

sleep 实现暴力的阻塞,但是不是优雅的(我们不知道子协程具体运行的时间)

计数器为 0 表示所有并发任务执行完成

package concurrence
​
import (
    "fmt"
    "sync"
)
func hello(i int){
  println("hello goroutine : " + fmt.Sprint(i))
}
​
func HelloGoRoutine(){
  var wg sync.WaitGroup // go标准库的一个同步工具,用于等待一组 goroutine
  for i := 0; i < 5; i++{
    go func(j int){ 
      defer wg.Done()// 在每个 goroutine 的函数体结束被调用,确保在函数执行完毕时减少等待的 goroutine 数量。
      hello(j)
    }(i) 
  }
  wg.Wait()
}

引入sync.WaitGroup,会在所有goroutine完成任务后才允许主线程继续执行

依赖管理

依赖是各种开发包

  • 工程项目不可能根据标准库从0~1搭建

go的依赖管理:gopath -> go vendor -> go module

现在广泛应用的就是 go module

  • 不同环境依赖的版本不同
  • 控制依赖库的版本

2.1 GOPATH

缺点是 无法实现package多版本控制

2.2 Go Vendor

多了一个 vendor 的文件,优先从 vendor 中找(把依赖代码一并带入项目);py 则是创建虚拟环境

vendor 也有问题

  • 无法控制依赖的版本
  • 更新项目可能出现依赖冲突,导致编译错误

Go Module

go module 是go官方出的一个依赖管理系统,解决了上述的问题,实现了定义版本规则和管理项目依赖关系的目标

  • 通过go.mod文件管理依赖包版本
  • 通过go get/go mod指令工具管理依赖包
依赖管理三要素
  1. 配置文件,描述依赖 go.mod
  2. 中心仓库管理依赖库 Proxy
  3. 本地工具 go get/mod (类似于爪哇的maven)
依赖配置
  • 版本的语义化定义

    MAJOR MINOR PATCH

    • MAJOR

      大版本,不同MAJOR间是代码隔离的

    • MINOR

      新增函数,功能,在 MINOR 下要做到兼容

    • PATCH

      代码版本的修复

  • 基于 commit 伪版本

版本前缀(语义化)— 时间戳 — 提交12位的哈希前缀

关键字
  • indirect 标识为非直接依赖
  • 主版本 v2 以上 v3 v4 这种,路径都需要增加 /v3 这种后缀,允许不同版本之间是不相互兼容的
  • incompatible 对没有 go.mod 文件并且主版本 2+ 的依赖,会标记一下,可能存在不兼容的代码。
依赖图

Go会通过算法选择最低兼容版本

依赖分发

这部分我们关注依赖去哪里下载,如何下载?

我们如果直接使用代码托管平台(Github, SVN, ...)下载下来的话,会有一些问题

  • 无法保证构建稳定性/可用性(增/删/改软件版本)
  • 增加第三方压力(平台负载问题)

所以出现了 Proxy没有什么是添加一个中间层解决不了的

Go moudle 是通过环境变量 GOPROXY 控制 Proxy 的

GOPROXY="https://proxy1.cn,https://proxy2.cn ,direct"

服务站点URL列表,“direct” 表示源站

先从 Proxy1 -> Proxy2 -> Direct;这和我们设计缓存的一些模式是相通的。

go get

go get 是 Go 语言的一个命令,用于 下载和安装 Go 包,并且自动更新项目中使用的依赖项。它可以从 GitHub、GitLab、Bitbucket 等代码托管平台

go mod

go mod 是 Go 语言用来管理依赖和模块的命令,它引入了 Go Modules 功能,从 Go 1.11 开始,旨在取代传统的 GOPATH 模式,使得 Go 语言的依赖管理更加简洁、可靠和可扩展。