「Go 语言上手-工程实践」
语言进阶
了解go高性能的本质以及golang为什么这么快
并发 vs 并行
- 并发
- 多线程程序在单核CPU上的执行 ,通过CPU时间片的快速切换去达到程序同时执行的效果。
- 并行
- 多线程程序在多核CPU上的执行,不行的程序运行在不同的核上,是正真意义上的并行(同时执行),并行是实现并发的一种手段。
go协程goroutine
较线程相比,协程是用户态的一种资源,创建代价比较小,协程栈在KB
级别,协程的创建由go语言本身去实现;相反线程是内核态的一种资源,其创建和销毁的代价比较大,线程栈在MB
级别。
协程通信
在golang中提倡通过通信来共享内存,而不是通过共享内存来实现通信。如果要用共享内存实现通信的话就需要对其进行互斥操作。
Channel/通道
- 创建通道的方式
// type表示元素类型,buffer_size表示缓冲区大小
make(chan type,[buffer_size])
//创建无缓冲通道
make(chan int)
//创建有缓冲通道
make(chan int, 4)
-
无缓冲通道
vs
有缓冲通道- 无缓冲的通道又称为阻塞的通道,无缓冲的通道只有在有人接收值的时候才能发送值。就像你住的小区没有快递柜和代收点,快递员给你打电话必须要把这个物品送到你的手中,简单来说就是无缓冲的通道必须有接收才能发送。
- 使用无缓冲通道进行通信将导致发送和接收的goroutine同步化。因此,无缓冲通道也被称为同步通道。
-
有缓冲通道就像你小区的快递柜只有那么个多格子,格子满了就装不下了,就阻塞了,等到别人取走一个快递员就能往里面放一个。
WaitGroup
在代码中生硬的使用time.Sleep肯定是不合适的,因为我们不能精确的知道程序执行的一个时间。go语言中可以使用sync.WaitGroup来实现并发任务的同步。
sync.WaitGroup有以下几个方法:
方法名 | 功能 |
---|---|
(wg * WaitGroup) Add(delta int) | 计数器+delta |
(wg *WaitGroup) Done() | 计数器-1 |
(wg *WaitGroup) Wait() | 阻塞直到计数器变为0 |
sync.WaitGroup内部维护着一个计数器,计数器的值可以增加和减少。例如当我们启动了N 个并发任务时,就将计数器值增加N。每个任务完成时通过调用Done()方法将计数器减1。通过调用Wait()来等待并发任务执行完,当计数器值为0时,表示所有并发任务已经完成。
依赖管理
- 不同环境/项目依赖的版本不同
- 控制依赖库的版本
GOPATH

- bin:项目编译的二进制文件
- pkg:项目编译的中间产物,可加速编译
GOPATH
弊端
如上图所示,A和B依赖某一pkg的不同版本,存在的问题:无法实现pkg多版本控制
GO Vendor
在项目目录下增加
vendor
文件夹,所有依赖包副本形式放在$project/vendor
下,优先从该文件夹下去获取依赖
Go Vendor
弊端
如上图所示,项目A同时依赖package B和package C,package B 和package C同时依赖package D(D有V1和V2两个版本),利用vendor
的方式就不能控制V1和V2的选择(本质上是因为vendor
还是依赖的项目的源码),于是就是出现下面问题:
- 无法控制依赖的版本
- 更新项目又可能出现依赖冲突,导致编译出错
Go Module
定义版本规则和管理项目依赖关系
- 通过
go.mod
文件管理依赖包版本 - 通过
go get/go mod
指令工具管理依赖包
依赖管理三要素
- 配置文件,描述依赖
go.mod
- 中心仓库管理依赖库
Proxy
- 本地工具
go get/mod
go.mod

依赖标识:
[Module Path][Version/Pseudo-version]
依赖配置-version
- 语义化版本
${MAJOR}.${MINOR}.${PATCH}
MAJOR
:大版本,不同的MAJOR
是可以不兼容的
MINOR
:新增一些功能函数,在大版本基础上是兼容的
PATCH
:代码bug修复
v1.3.0
v2.3.0
- 基于
commit
伪版本
版本前缀(和语义化版本一致)-
时间戳(提交本次commit的时间戳)-
提交commit12位的hash码
v0.0.0-20180306012644-bacd9c7ef1dd
依赖配置-indirect
存在: A->B->C
A直接依赖B,A间接依赖C,在go.mod
中对于没有直接依赖的标识为indirect
,如上图所示
依赖配置-incompatible
依赖分发-Proxy
表示项目依赖应该去哪里下载
直接使用第三方平台的话会存在以下问题:
- 无法保证构建稳定性,比如存在增加、修改、删除软件版本的话,后续构建可能会存在依赖找不到了,导致构建失败
- 无法保证依赖的可用性,比如依赖仓库被删除了
- 增加第三方压力
为了解决以上问题,就有了GOPROXY
GOPROXY
是一个服务站点,会缓存源站中的软件内容,缓存的软件版本不会改变,并且源站软件删除之后依然可用,从而实现稳定和可靠的依赖分发。
// 项目依赖查找顺序proxy1->proxy2->direct
// 如果在前面都没有找见,则直接到源站查找
GOPROXY="https://proxy1.cn,https://proxy2.cn,direct"
工具 go mod
go mod init //初始化,创建go.mod文件
go mod download //下载模块到本地缓存
go mod tidy // 增加需要的依赖,删除不需要的依赖
工具 go get
go get example.org/pkg
@update //获取默认的依赖包
@none //删除依赖
@v1.2.2 //获取对应语义版本的依赖包
@23dfff3 //获取对应commit的依赖
@master //获取最新分支的依赖包
//比如
go get code.byted.org/tmq/tmq@v1.5.30
转载自:https://juejin.cn/post/7124500176932175879