这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天,主要是复习了一下Go语言的并发编程,了解了一下Go语言里面依赖管理的最佳实践和学习了单元测试的相关知识
并发编程
Go语言的优势
在传统的编程语言中,基于多线程模型的应用设计就是一种典型的并发程序设计。它们多以传统操作系统线程作为承载分解后的代码片段(模块)的执行单元,由操作系统执行调度。但线程的创建、切换以及销毁的代价都比较大。
Go语言的设计哲学之一是"原生并发,轻量高效",意味着Go天然支持高并发。在Go语言中实现了goroutine这一由Go运行时负责调度的用户层轻量级协程为并发程序设计提供原生支持
Go语言之父,Rob Pike说过,不要通过共享内存来通信,而应该通过通信来共享内存。传统的编程语言的并发模型是基于共享内存的并发模型,导致其很难用而且易错。而Go语言依据CSP模型,设计出了一种基于通信来共享内存的并发模型,Go同时也保留了传统的基于共享内存的并发模型,但Go始终推荐以CSP模型风格构建并发程序
Go的并发操作
在Go语言中,可以通过Go关键字来开启一个协程,比如
func AddWithoutLock(a int) {
for i := 0; i < 2000; i++ {
x++
}
}
func main() {
x = 0
for i := 0; i < 5; i++ {
go AddWithoutLock(i)
}
}
这个例子中,在for循环里调用了5次go关键字,因此开启了5个协程
channel
channel,又称管道,是Go常见的并发模式中的一种,它对应CSP模型中的输入/输出原语,用于协程之间的通信和同步。可以通过make()函数来创建一个管道
channel := make(chan int, 5)
上述例子创建了一个能够存放int类型数据的管道
在Go中channel分为无缓冲channel和带缓冲channel,区分一个channel是否带缓冲只需要观察创建channel的make()函数是否带有第二个参数,如上面例子中的5。若带有参数则为带缓冲channel,缓冲大小即为数字大小
无缓冲channel兼具通信和同步的特性。由于其不带缓冲区,因此对无缓冲channel的接收和发送操作是同步的,即对于同一个无缓冲channel,只有在对其进行接收操作的goroutine和对其进行发送操作的goroutine都存在的情况下通信才能进行,否则单方面的操作会让对应的goroutine陷入阻塞
带缓冲channel可以通过带有capacity参数内置的make函数创建。由于带有缓冲,因此channel的发送操作在缓冲区未满、读取操作在缓冲区非空时是异步的,即只有在缓冲区为空并且对channel进行读取操作,在缓冲区满了并且对channel进行发送操作才会导致对应的goroutine陷入阻塞
后面对于依赖管理和单元测试了解得还不够多,所以本篇笔记先到这了