Go语言进阶 | 青训营笔记

84 阅读3分钟

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

本篇笔记主要包含以下内容:

  1. 从并发编程的视角了解Go高性能的本质;
  2. Go语言依赖管理;
  3. 单元测试;
  4. 项目实战。

一、 从并发编程的视角了解Go高性能的本质

1.协程(Goroutine)

(1)特点:用户态、轻量级线程,栈MB级别,用于执行并发任务,线程跑多个协程; (2)使用方法:调用函数时在函数前加go关键字。

go 函数名(参数列表)

(3)扩展:Sleep阻塞,保证在子协程执行完之前主协程不退出。 time.Sleep(time.Second)

image.png

2.通信顺序进程(CSP)

(1)go提倡通过通信共享内存而不是通过共享内存而实现通信。 (2)go拥有通信共享内存和通过共享内存而实现通信两种方式。 (3)由协程Goroutine与通道Channel实现。

image.png

3.通道(Channel)【通过通信共享内存】

(1)定义:Channel是一种引用类型, 在 gouroutine 间架起了一条管道,在管道里传输数据,实现 gouroutine 间的同步、通信;由于它是线程安全的,所以用起来非常方便;channel 还提供 “先进先出” 的特性;它还能影响 goroutine 的阻塞和唤醒。

(2)使用:make(chan 元素类型,【缓冲大小】)

(3)分类:

  • 无缓冲通道:make(chan int)
  • 有缓冲通道:make(chan int,2)

使用无缓冲通道会让通信的两个gorountine同步化,所以无缓冲通道也称为同步通道;使用有缓冲通道则可以解决同步问题。

image.png

(4)扩展:资源延迟关闭。 defer close(src)

4.并发安全Lock【通过共享内存而实现通信】

(1)使用lock保护临界区:输出结果符合预期值。

lock.lock() //执行代码 lock.Unlock()

(2)不使用lock保护临界区:输出结果低于预期值,存在并发安全的问题。

5.WaitGroup(计数器)

(1)Add(delta int):开启协程+1;

(2)Done():执行结束-1;

(3)Wait():主协程阻塞直到计数器为0。

(4)优化:

image.png 变为

image.png

①需要五个协程;②在每个协程结束后,通过Done()方法对协程减一;③通过Wait()进行阻塞。

二、 Go语言依赖管理

1.依赖管理演进:

演进过程--其中Go Module使用广泛。

image.png

目的:

  • 不同环境(项目)依赖的版本不同
  • 控制依赖库的版本

(1).GOPATH

  • $GOPATH环境变量,是go项目的工作区。

bin-项目编译的二进制文件; pkg-项目编译的中间产物,加速编译; src-项目源码。

  • 项目代码直接依赖src下的代码
  • go get下载最新版本的包到src目录下
  • 弊端:无法实现package的多版本控制。

(2)Go Vendor

  • 方法:

通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package依赖的冲突问题。

项目目录下增加vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor

依赖寻址方式: vendor => GOPATH

  • 弊端:

依赖项目源码,不能很清晰的标识依赖版本的概念。

无法控制依赖的版本。

更新项目又可能出现依赖冲突,导致编译出错。

(3)Go Module

  • 通过go.mod文件管理依赖包版本;
  • 通过go get/go mod指令工具管理依赖包;
  • 终极目标:定义版本规则和管理项目依赖关系。

2.依赖管理三要素

(1)配置文件,描述依赖go.mod

(2)中心仓库管理依赖库Proxy

(3)本地工具go get/mod

3.依赖配置 (1)go.mod

image.png

(2)version

  • 语义化版本 ${MAJOR}.${MINOR}.${PATCH}

不同MAJOR可以不兼容;MINOR做到前后兼容;PATCH做一些代码和BUG的修复。

V1.3.0 V2.3.0

  • 基于commit伪版本

vX.0.0-yyyymmddhhmmss-abcdefgh1234

版本前缀-时间戳-12位哈希校验码

v0.0.0-20220401081311-c38fb59326b7 v1.0.0-20201130134442-10cb98267c6c

(3)indirect 将没有直接导入的依赖模块标识为非直接依赖,用indirect标识出来。

(4)incompatible

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

(5)依赖图

  • 选择最低的兼容版本