0003.Go 语言进阶与依赖管理 | 青训营笔记
[TOC]
一、语言进阶
1.并发 VS 并行
1多线程程序在一个核的cpu上运行 2多线程程序在多个核的cpu上运行
==Go 可以充分发挥多核优势,高效运行==
2.Goroutine
goroutine是Go并发设计的核心,也叫协程,它比线程更加轻量,因此可以同时运行成千上万个并发任务。
不仅如此,Go语言内部已经实现了goroutine之间的内存共享,它比线程更加易用、高效和轻便。
来看看线程与协程的区别:
==协程==:用户态,轻量级线程,==栈 KB级别== ==线程==:内核态,线程跑多个协程,==栈MB级别==
在 Go 语言中,有一个关键字 go 可以创建一个新的协程。你可以在任意一个可执行的 Go 函数前加上 go 关键字即可创建一个新协程。
2.CSP (Communicating Sequentisl Procesees)
提倡通过==通信共享内存==而不是通过共享内存而实现通信
3.Channel
make(chan 元素类型,[缓冲大小])
- 无缓冲通道make(chan int)
- 有缓冲通道make(chan int,2)
4.并发安全 Lock
5.WaitGroup
==计数器== 开启协程+1: 执行结束-1;主协程阻塞直到计数器为0.
6.Goroutine 小结
优点:
1、开销小
POSIX的thread API虽然能够提供丰富的API,例如配置自己的CPU亲和性,申请资源等等,线程在得到了很多与进程相同的控制权的同时,开销也非常的大,在Goroutine中则不需这些额外的开销,所以一个Golang的程序中可以支持10w级别的Goroutine。
每个 goroutine (协程) 默认占用内存远比 Java 、C 的线程少(goroutine:2KB ,线程:8MB)
2、调度性能好
在Golang的程序中,操作系统级别的线程调度,通常不会做出合适的调度决策。例如在GC时,内存必须要达到一个一致的状态。在Goroutine机制里,Golang可以控制Goroutine的调度,从而在一个合适的时间进行GC。
在应用层模拟的线程,它避免了上下文切换的额外耗费,兼顾了多线程的优点。简化了高并发程序的复杂度。
缺点:
协程调度机制无法实现公平调度。
二、依赖管理
1.背景
- 工程项目不可能基于标准库0-1编码搭建
- 管理依赖库
2.Go依赖管理演进
GOPATH→Go Vendor→Go Module
- 不同环境 (项目)依赖的版本不同
- 控制依赖库的版本
3.GOPATH
环境变量$GOPATH
- 项目代码直接依赖 src下的代码
- go get 下载最新版本的包到 src目录下
在 GOPATH 的 $GOPATH/src 下进行 .go 文件或源代码的存储,我们可以称其为 GOPATH 的模式,这个模式拥有一些弊端。
- A. 无版本控制概念. 在执行go get的时候,你无法传达任何的版本信息的期望,也就是说你也无法知道自己当前更新的是哪一个版本,也无法通过指定来拉取自己所期望的具体版本。
- B.无法同步一致第三方版本号. 在运行 Go 应用程序的时候,你无法保证其它人与你所期望依赖的第三方库是相同的版本,也就是说在项目依赖库的管理上,你无法保证所有人的依赖版本都一致。
- C.无法指定当前项目引用的第三方版本号. 你没办法处理 v1、v2、v3 等等不同版本的引用问题,因为 GOPATH 模式下的导入路径都是一样的,都是github.com/foo/bar。
4.Go Vendo
- 项目目录下增加 vendor 文件,所有依赖包副本形式放在 $ProjectRoot/vendor
- 依赖寻址方式: vendor => GOPATH
通过每个项目引入一份依赖的副本解决了多个项目需要同一个 package依赖的冲突问题。
Go Vendor的弊端:
- 无法控制依赖的版本
- 更新项目又可能出现依赖冲突,导致编译出错
5. GoModule
- 通过go.mod 文件管理依赖包版本
- 通过 go get/go mod 指令工具管理依赖包
终极目标: 定义版本规则和管理项目依赖关系
6.依赖管理三要素
- 配置文件,描述依赖 go.mod
- 中心仓库管理依赖库 Proxy
- 本地工具 go get/mod
7.依赖配置- go.mod
module example/project/dpp 依赖管理基本单元
go 1.16 原生库
reguire( 单元依赖
example/libl v1.0.2
example/lib2 v1.0.0 // indirect
example/lib3 v0.1.0-20190725025543-5a5fe074e612
example/lib4 v0.0.0-20180306012644-bacd9crefldd /y indirect
example/lib5/v3 v3.0.2
example/lib6 v3.2.0+incompatible
)
语义化版本
${MAJOR}.${MINOR}.${PATCH}
V1.3.0
V2.3.0
基于 commit 伪版本
wx.0.0-yyyymmddhhmmss-abcdefgh1234
v0.0.0-20220401081311-c38fb59326b7
v0.0.0-20201130134442-10cb98267c6c
依赖标识: [Module Path] [Version/Pseudo-version]
依赖配置- indirect
依赖配置- incompatible
8.依赖分发
回源:
-
无法保证构建稳定性 增加/修改/删除软件版本
-
无法保证依赖可用性 删除软件
-
增加第三方压力 代码托管平台负载问题
依赖分发-Proxy
依赖分发-变量 GOPROXY GOPRQXY="httpe://proxy1.cn, proxy2.cn ,direct" 服务站点URL列表,“direct"表示源站
9.工具
工具-go get:
go get example.org/pkg
- 默认 @update
- 删除依赖 @none
- tg版本,语义版本 @v1.1.2
- 特定的commit @23dfdd5
- 分支的最新commit @master
工具-go mod:
go mod
- 初始化,创建go.mod文件 init
- 下载模块到本地缓存 download
- 增加需要的依赖,删除不需要的依赖 tidy