本堂课重点内容:
- GO的并发
- GO的依赖管理
- Go的测试
- GO的包管理
- Go的web项目
知识点
GO的并发编程
Go语言的优势与特点
简单的协程示例
package main
import (
"fmt"
"time"
)
func hello(i int) {
fmt.Println("hello go:", i)
}
func main() {
for i := 0; i < 5; i++ {
go func(j int) {
hello(j)
}(i)
}
time.Sleep(time.Second)
}
Channel:
make(chan 元素类型,[缓冲大小])
Lock
就是一把锁,可以解决多线程下资源的同步问题
//Mutex 是互斥锁, 零值是解锁的互斥锁, 首次使用后不得复制互斥锁。也就是题目中的锁
如果对一个已经上锁的对象再次上锁,那么就会导致该锁定操作被阻塞,直到该互斥锁回到被解锁状态
基本使用如下
xxx.lock()
代码
xxx.unlock()
Go语言还有读写锁,用途更加专业
而其实当我们对一个固定的资源只做“读”操作的话,是不存在资源竞争的问题的,也就不会引发竞态。因为数据是不变的,不管怎么读取,多少goroutine同时读取都没有问题。
package main
import (
"fmt"
"sync"
"time"
)
//全局变量
var end int
var rLock sync.RWMutex
func Read(i int) {
rLock.RLock()
fmt.Printf("读 goroutine%d 结果:%d\n", i, end)
defer rLock.RUnlock()
}
func Write(i int) {
rLock.Lock()
end = end + i
fmt.Printf("写 goroutine%d 结果:%d\n", i, end)
defer rLock.Unlock()
}
func main() {
for i := 0; i < 5; i++ {
go Write(i)
}
for i := 0; i < 5; i++ {
go Read(i)
}
time.Sleep(time.Second * 120)
}
结果如下
写 goroutine0 结果:0
读 goroutine1 结果:0
读 goroutine0 结果:0
读 goroutine2 结果:0
读 goroutine3 结果:0
读 goroutine4 结果:0
写 goroutine2 结果:2
写 goroutine1 结果:3
写 goroutine3 结果:6
写 goroutine4 结果:10
可以看出当所有的读取之后才会进入写的状态
第一个写入是因为程序还未运行读的线程
WaitGroup
Go语言中除了可以使用**通道(channel)**和互斥锁进行两个并发程序间的同步外,还可以使用等待组进行多个任务的同步,等待组可以保证在并发环境中完成指定数量的任务
WaitGroup的用途是使得主线程一直阻塞等待直到所有相关的子goroutine都已经完成了任务。
在 sync.WaitGroup(等待组)类型中,每个 sync.WaitGroup 值在内部维护着一个计数,此计数的初始默认值为零。
等待组有下面几个方法可用,如下表所示。
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
println("hello")
}()
}
wg.Wait()
}
使用 Add
添加需要等待的个数,使用 Done
来通知 WaitGroup 任务已完成,使用 Wait
来等待所有 goroutine 结束。
包管理
Go的包管理非常依靠网络,我看视频的基本都是从github上自动导入
包。
目前使用主流使用GoMod管理依赖
使用go mod管理依赖
go mod init
初始化gomod文件
go mod downlaod 下载模块到本地
go mod tidy 添加依赖,删除不用的依赖
Go的测试
规则:
- 所有测试文件以xxx_test.go结尾
- fun TestXxx(*tesing.T)
- 初始化逻辑放在TestMain中
代码覆盖率是指在测试中运行过的行数/总行数
理想情况下为100%
*go test 命令,会自动读取源码目录下面名为 _test.go 的文件,生成并运行测试用的可执行文件。
基准测试可以测试一段程序的运行性能及耗费 CPU 的程度。
参数如下
go test -v go_test.go -timeout=20m -count=1
- -v 打印详情测试信息
- -timeout 默认10分钟超时
- -count 函数运行几次
go get 参数
参数介绍:
- -d 只下载不安装
- -f 只有在你包含了 -u 参数的时候才有效,不让 -u 去验证 import 中的每一个都已经获取了,这对于本地 fork 的包特别有用
- -fix 在获取源码之后先运行 fix,然后再去做其他的事情
- -t 同时也下载需要为运行测试所需要的包
- -u 强制使用网络去更新包和它的依赖包
- -v 显示执行的命令
示例
go get -u github.com/gin-gonic/gin
课后总结
Go的并发具有很大的优势,比java简单的多了,工具也比java快得多。
但是包管理不如java
web开发简单,容易上手