这是我参与「第五届青训营」笔记创作活动的第2天
今天讲的内容主要是三个部分,协程控制、依赖管理、测试
协程
认识协程前先回顾一下什么是进程和线程
进程:
- 拥有资源分配的基本单位
- 进程是一个独立的单位,有独立的内存空间
线程:
- 调度和分配的基本单位
- 共享进程资源内存等方式线程间通信
- 线程可以创建和取消另一个线程,进程间线程并发执行
- 易调度,开销少,可并发,创建线程比创建进程开销少
区别:
- 一个 线程只能属于一个进程,而一个进程可以有多个线程,至少一个线程
- 资源分配给进程,同一进程的线程共享资源
- 真正执行处理的是线程,进程内的一个执行单位,可调度实体
- 线程不拥有系统资源,但可以访问隶属于进程的资源
- 分配和回收资源时,进程开销明显大于线程
下面请出协程:
- 协程是一种更轻量级的线程,不受操作系统直接调度,而是由用户应用程序提供的协程调度器按照调度策略调度到线程执行
- Go协程调度器由runtime包提供,go关键字创建协程
- 用户态的协程可以减少切换开销,协程调度器可以把可调度的协程给线程执行,同时把阻塞的协程调度出协程
并发控制
在go语言中更提倡的是通过通信共享内存,而不是共享内存的方式实现通信
channel
通过channel可以很简单的实现一个协程控制的过程
func main() {
channels := make([]chan int, 10)
for i := 0; i < 10; i++ {
channels[i] = make(chan int)
go process(channels[i])
}
for i, ch := range channels {
<-ch
fmt.Println("子协程", i, "退出")
}
}
func process(ch chan int) {
time.Sleep(time.Second)
ch <- 1
}
WaitGroup
通过信号量的方式控制协程
主要就是3个接口方法 Add、Wait、Done
type WaitGroup struct {
noCopy noCopy // 锁
state1 uint64 // 两个计数器
//counter当前还未执行结束的goroutine计数器,waiter等待goroutine结束的goroutine数量
state2 uint32 // 信号量
}
func main(){
var wg sync.WaitGroup
wg.Add(5)
for i:= 0;i<5;i++{
go func(j int){
defer wg.Done()
fmt.Println("HelloWorld")
}
}
wg.Wait()
}
依赖管理
go语言的依赖管理有三个阶段性的变化
GoPath的弊端
多个项目依赖同一个库时,不同项目不能依赖同一个库的不同版本
GoVendor的弊端
无法控制依赖的版本,更新项目时又可能出现依赖冲突的问题
GoModule
提供了go.mod文件来对依赖包版本的管理,可以通过go get/mod 等指令工具管理依赖包
测试
单元测试
单元测试覆盖率,一般覆盖率50%~60%,较高覆盖率80%+
基准测试
基准测试也就是测试一段程序的运行性能及CPU开销
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
AAA()
}
}
func AAA() func(t testing.T) {
return func(t testing.T) {
t.Run("test1", add1)
t.Run("test2", add2)
t.Run("demo3", add3)
}
}
好了,今天也就告一段落了,明天再开始新的一天的学习了,加油鸭