Go语言并发与依赖管理 | 豆包MarsCode AI刷题

108 阅读2分钟

并发

  • 线程: 内核态, 线程跑多个协程, 栈空间MB级
  • 协程: 用户态, 轻量级线程, 栈空间KB级
  • channel 通道: make(chan 元素类型, [缓冲大小(>=2为有缓冲通道)])
  • lock 并发安全: sync.Mutex定义互斥锁
  • WaitGroup 等待组: sync.WaitGroup定义等待组, Add(delta uint)计数器增加delta, Done()计数器减1, Wait()阻塞直到WaitGroup为0
  • 原子函数(atomic):atomic包提供了对数值类型的原子操作,如atomic.AddInt64()atomic.LoadInt64()atomic.StoreInt64()等完成加法、读和写操作
  • 互斥锁(sync/mutex):通过mutex.lock()mutex.unlock()创建临界区,临界区内的代码同一时刻只能有一个goroutine执行
  • 通道可用于共享资源的发送和接收,通过关键字chan声明,通过make()函数创建
    • unbuffered := make(chan int): 无缓冲区管道
    • buffered := make(chan int, 10): 有缓冲区管道,大小为10个int
    • `value := <-buffered`:从有缓冲区管道中接收一个值,`<-`操作符用于接收和发送
      
  • var wg sync.WaitGroup创建信号量
  • wg.wait()会阻塞调用它的goroutine直到计数器减为0,wg.add()会增加计数器的值,wg.done()会减少计数器的值
  • 当通道关闭后,goroutine依旧可以从通道接收数据,但是不能再向通道里发送数据
  func (r *Runner) Add(tasks ...func(int)) {
  	r.tasks = append(r.tasks, tasks...)
  }
  • 参数列表中的...表示可以接收任意数量的参数,func(int)表示函数类型,表示接收一个参数为int类型的并且不返回任何值的函数
  • select用于多个通道的发送和接收操作,select会阻塞纸质任一个case可以执行,如果有default则不会阻塞,没有信号时直接执行default

依赖管理

  • GOPATH管理模式: 项目代码直接依赖src下代码, go get将最新版本的包加到src下
    • ./bin 项目编译的二进制文件
    • ./pkg 项目编译的中间产物
    • ./src 项目源码
    • 缺点: 无法实现pkg的多版本控制
  • Go Vender管理模式: 在项目目录下增加vender文件夹, 所有依赖包以副本形式存放于$ProjectRoot/vender, 首先vender=>GOPATH
    • 当一个项目直接/间接依赖了同一个包的多个版本时, 出现不兼容, 还是由于vender无法控制包的依赖版本
  • Go Module管理模式: 1.16开始使用, 定义版本规则和项目依赖关系
    • go.mod: 管理依赖包版本
    • go get/go mod指令来管理依赖包
  • 依赖管理三要素
    • 配置文件描述依赖 go.mod
    • 中心仓库管理依赖库 Proxy
    • 本地工具 go get/mod
  • 依赖配置
    • version * 语义化版本 ${MAJOR}.${MINOR}.${PATCH} * 基于commit的伪版本 ${MAJOR}.${MINOR}.${PATCH}-${timestamp}-${hash-checksum}
    • indirect 间接依赖
    • incompatible 主版本2+模块需要加/vN后缀, 如果没有go.mod文件且主版本为2+的依赖要使用incompatible
  • 依赖分发-Proxy: 缓存托管平台分发版本, 保证依赖的稳定可靠
    • GOPROXY="URL_ADDRESS1, URL_ADDRESS2,..., direct", 从前往后找, direct为源站
  • 工具
    • go get 下载并安装指定版本的包和依赖包
      • @update默认方法/@none删除依赖/@vN指定语义版本
    • go mod
      • init 初始化创建go.mod
      • download 下载模块到本地缓存
      • tidy 添加缺少的模块, 并删除不需要的模块