GO语言进阶|青训营笔记

81 阅读3分钟

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

go语言进阶

goroutine

前置知识:协程和线程的概念

线程是内核态的,MB级别。

我们知道进程是操作系统分配资源的最小单位,但进程之间的切换开销较大,所以引入线程作为程序执行的最小单位。

一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线。

同一进程下的不同线程之间是有共享的内存空间和资源的(打开的文件或者信号),进程内的线程在其他进程是不可见的。

协程是用户态的,可以将其理解为轻量级的线程,kb级别。一个线程上可以并发的跑多个协程,协程的调度不同于由os内核完成的线程,他由用户完成。

Goroutine的相关知识(启动、控制等等)

goroutine的csp模型。 go通过通信共享内存而不是通过共享内存实现通信。 通信共享内存可以在一定程度上避免数据竞态

csp.jpg

go利用channel完成通信。 有无缓冲通道和有缓冲通道两类。

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

生产消费模型是对他们在工程应用的一个例子。
比如生产消费模型中,由生产数据的协程和消费数据的协程组成。我们无法保证消费方消费数据的速度,因此这里需要使用带缓存的通道对生产的数据进行缓存。

其次对于并发安全,有lock的方式可以用来实现

在处理共享数据之前,先将此协程上锁,防止待处理的共享数据被其他协程篡改导致最终结果出错。在处理共享数据之后将数据解锁。允许其他协程的操作。

waitgroup可以用来实现线程同步

wait方法利用waitgroup进行阻塞等待,阻塞到计数器为0为止。
add方法用于初始化一个计数器。
Done方法用于累减计数器。

同步的示例:使用add初始化好计数器,在主程中由wait进行阻塞等待,协程每完成一次任务调用done使计数器自减,当计数器自减为0时,wait不再阻塞。主程向下进行。

依赖管理

go的依赖管理经历了gopath、go vendor、go moudle的演进过程

gopath环境变量下存在这样的结构: bin、pkg、src的同级目录。 bin存储项目的编译文件, pkg存储项目编译的中间产物,可以加速编译 src作为项目源码存储源码

弊端:对于依赖于同一个包的不同版本的代码,无法实现包的多版本控制。

go vender利用存储依赖包副本的方式解决依赖冲突的问题。
他会在项目文件下增加一个vendor文件,用于存储副本。

弊端:无法控制依赖的版本,更新项目又可能出现依赖冲突。依赖项目的源码并不能很清晰的标识依赖的版本。

go moudle利用go get/go mod指令工具管理依赖包,管理文件是go.mod go mod的终极目标在于定义版本规则和管理项目的依赖关系。

go mod 的三要素:

  1. 配置文件。描述依赖。 go.mod
  2. 中心仓库管理依赖库 Proxy
  3. 本地工具 go get/mod

go.mod的依赖配置分为语义化版本、基于commit的伪版本
语义化版本: “MAJOR.{MAJOR}.{MINOR}.${PATCH}”
基于commit的伪版本:vX.0.0-yyyymmddhhmmss-abcdefgh1234
go.mod文件会用//indirect描述间接依赖。 模块版本高于v2应当存在后缀,对于不存在于go.mod文件并且主版本2+的依赖,会在后面添加“+incompatible”进行标识。这种依赖可能会发生代码不兼容的情况。

依赖分发使用了proxy
在proxy站点没有相应依赖的情况下,会去回源到源站查找。