课程目录
1. 语言进阶(并发编程)
2. 依赖管理(go module)
-
测试(单元测试)
-
项目实战
1. 语言进阶
并发 vs 并行
并发:多线程程序在一个核的 cpu 上运行
并行:多线程程序在多个核的 cpu 上运行
goroutine:轻量级线程,可以认为几乎不占用内存(KB 级别),可以轻松开启很多 goroutine(golang 在语言层面实现了并发)
代码实例
func HelloGoRoutine() {
for i := 0; i < 5; i++ {
go func(j int) {
fmt.Println(j)
}(i)
}
time.Sleep(1 * time.Second)
}
golang 提倡通过通信共享内存,而不是共享内存来通信(遵循 CSP 通信模型,Communicating Sequential Processes)
协程间通信可以通过 channel 实现,channel 包含无缓冲通道和有缓冲通道两种,无缓冲通道又称为同步通道,有缓冲通道也称为异步通道
代码实例
A 子协程发送 0~9 数字
B 子协程计算输入数字的平方
主协程输出最后的平方数
func CalSquare() {
src := make(chan int)
// 在消费端使用有缓冲通道,防止消费速度影响生产者的生产速度
dest := make(chan int, 3)
// A
go func() {
defer close(src)
for i := 0; i < 10; i++ {
src <- i
}
}()
// B
go func() {
defer close()
for i := range src {
dest <- i * i
}
}()
// 主 goroutine
for i := range dest {
fmt.Println(i)
}
}
并发安全 Lock
代码实例
var (
x int64
lock sync.Mutex // sync 包中的 Mutex 是并发安全的
)
func addWithLock() {
for i := 0; i < 2000; i++ {
lock.Lock()
x++
lock.Unlock()
}
}
func addWithoutLock() {
for i := 0; i < 2000; i++ {
x++
}
}
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)
}
WaitGroup
wg.Add(): 开启一个协程,计数器 +1
wg.Done(): 一个协程结束,计数器 -1
wg.Wait(): 主 goroutine 阻塞,直到计数器值为 0(等待子 goroutine 结束)
代码实例
func ManyGoWait() {
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()
}
2. 依赖管理
发展历程:GOPATH -> Go vendor -> Go Module
GOPATH 弊端:无法实现 package 的多版本控制
Go vendor:所有依赖包副本形式放在 vendor 文件夹中,无法控制依赖的版本,更新项目有可能出现依赖冲突,导致编译出错
Go Module:通过 go.mod 文件管理依赖包版本,通过 go get,go mod 指令工具管理依赖包
- go mod init example/xyz 初始化,新建 go.mod 文件
- go mod download 下载模块到本地缓存
- go mod tidy 增加需要的依赖,清理不必要的依赖
- go get github.com/xyz/abc@version 获取指定版本的
依赖管理三要素
1、配置文件,描述依赖 (go.mod)
2、中心仓库管理依赖库(Proxy)
3、本地工具(go get/mod)
- go.mod
- version
语义化版本:${MAJOR}.${MINOR}.${PATCH}
v1.3.0
v2.3.0
基于 commit 的伪版本:vx.0.0-yyyymmddhhmmss-abcdefgh1234
v0.0.0-20220401081311-c38fb59326b7c
v1.0.0-202001130134442-10cb98267c6c
- indirect
- incompatible
- 依赖图
在依赖版本选择时,选择最低兼容版本,即使有 C 1.5版本,最终也会选择 C 1.4版本进行编译。
- 依赖分发
直接将依赖分发给第三方代码托管平台存在的问题
- 无法保证构建稳定性(软件作者可以直接在代码托管平台对软件版本进行增加、修改或删除)
- 无法保证依赖的可用性(软件作者可以对软件仓库进行删除)
- 增加了第三方的压力(代码托管平台的负载问题)
使用 PROXY
Golang 的 PROXY 是一个软件站点,它会缓存源站中的软件内容,缓存里的软件版本不会改变,可以保证可靠稳定的依赖分发.
- 变量 GOPROXY
GORPOXY="proxy1.cn, proxy2.cn, direct" 服务站点 URL 列表,“direct”表示源站
可以使用 go env | grep GOPROXY 查看 GOPROXY 的值
源码下载到本地的 /Users/apple/Public/青训营/day2