这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
入门 Go 语言-工程实战
协程
如何开启携程:在调用函数时在函数前添加go关键字
go语言提倡通过通信共享内存而不是通过共享内存而实现通信
package main
import (
"fmt"
"time"
)
func hello(i int) {
println("hello goroutine:", fmt.Sprint(i))
}
func main() {
for i := 0; i < 5; i++ {
go func(j int) {
hello(j)
}(i)
}
time.Sleep(time.Second)
}
通道
通过make(chan 元素类型,[缓冲大小])来创建通道
- 无缓冲通道
make(chan int) - 有缓冲通道
make(chan int,2)子协程A发送0-9,子协程B计算输入数字的平方,主协程输出最后的平方
func CalSquare() {
src := make(chan int)
dest := make(chan int, 3)
go func() {
defer close(src)
for i := 0; i < 10; i++ {
src <- i
}
}()
go func() {
defer close(dest)
for i := range src {
dest <- i * i
}
}()
for i := range dest {
fmt.Println(i)
}
}
并发安全锁🔒
对变量执行2000次+1操作,5个协程并发执行
package main
import (
"fmt"
"sync"
"time"
)
var x int64
var lock sync.Mutex
func addWithLock() {
for i := 0; i < 2000; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}
func addWithoutLock() {
for i := 0; i < 2000; i++ {
x += 1
}
}
func add() {
x = 0
for i := 0; i < 5; i++ {
go addWithoutLock()
}
time.Sleep(time.Second)
fmt.Println("Withoutlock", x)
x = 0
for i := 0; i < 5; i++ {
go addWithLock()
}
time.Sleep(time.Second)
fmt.Println("WithLock", x)
}
func main() {
add()
}
我们会发现有安全锁的输出了10000没有安全锁的输出了8382
等待组(WaitGroup)
WaitGroup提供的三个方法
Add(delta int)计数器+deltaDone()计数器-1Wait()阻塞知道计数器为0
func hello(i int) {
println("hello goroutine:", fmt.Sprint(i))
}
func MabyGoWait() {
var wg sync.WaitGroup
wg.Add(5)
for i := 0; i < 5; i++ {
go func(j int) {
defer wg.Done()
hello(j)
}(i)
}
wg.Wait()
}
依赖管理
GOPATH
- 环境变量$GOPATH
- 项目代码直接依赖src下的代码
- go get 下载最新版本的包到src目录下
弊端
- 无法实现package的多版本控制
GO Vendor
- 项目目录下增加vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor
- 依赖寻址方式:vendor => GOPATH
- 通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package依赖的冲突问题
弊端
- 无法控制依赖的版本
- 更新项目又可能出现依赖冲突,导致编译出错
GO Module
- 通过go.mod文件管理依赖包版本
- 通过go get/go mod指令工具管理依赖包
- 终极目标:定义版本规则和管理项目依赖关系
依赖管理三要素
- 配置文件,描述依赖
go.mod - 中心仓库管理依赖库
Proxy - 本地工具
go get/mod
依赖配置go.mode
module github.com/wangkechun/go-by-example //依赖管理基本单元
go 1.18 //原生库
//单元依赖
require (
)
依赖标识:[Module Path][Version/Pseudo-version]
依赖配置-version
语义化版本
${MAJOR}.${MINOR]}.${PATCH}
- V1.3.0
- V2.3.0
基于commit伪版本
- vX.0.0-yyyymmddhhmmss-abcdefgh1234
- vO.0.0-20220401081311-c38fb59326b7
- v1.0.0-20201130134442-10cb98267c6c
依赖配置-indirect
对于没有直接依赖的模块用//indirect标识出来
依赖配置-incompatible
- 主版本2+模块会在模块路径增加/vN后缀
- 对于没有go.mod文件并且主版本2+的依赖会+incompatible
依赖分发
- Github
- SVN
- 无法保证构建稳定性增加/修改/删除软件版本
- 无法保证依赖可用性删除软件
- 增加第三方压力代码托管平台负载问题
依赖分发-Proxy
- 稳定
- 可靠
依赖分发-变量 GOPROXY
工具- go get
go get example.org/pkg @update默认go get example.org/pkg @none删除依赖go get example.org/pkg @v1.1.2tag版本,语义版本go get example.org/pkg @23dfdd5特定的commitgo get example.org/pkg @master分支的最新commit
工具- go mod
go mod init初始化,创建go.mod文件go mod download下载模块到本地缓存go mod tidy增加需要的依赖,删除不需要的依赖