这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天 why go比较快
并发是指在一个核上运行多个线程 通过时间片轮换的方式(此外也有广义高并发)
并行可以说是实现并发的一种手段
go通过高效调度高效率利用计算资源,发挥多核计算机的优势
图中应该是协程是kb级别
go语言可以一次创建上万个协程
开多个协程去打印。只需要在函数调用之前加上一个go就可以为函数调用创建一个协程来运行
最后sleep是保证子协程跑完之前主线程不会退出
因为是并行打印所以可能是乱序的
通道相当于把协程做了一个连接,相当于一个队列能保证顺序。通道就是可以让一个goroutine发送特定值到另一个goroutine的机制
go仍然保留了通过共享内存实现通信(对临界区加锁,修改临界区,这样一定程度上会影响程序的性能,所以go提倡了通过通信来共享内存)
无缓冲通道又叫同步通道
有缓冲通道上的容量就是可以存放元素的大小,类比于货架,也可以认为是一个生产者消费者模型
src实现ab协程之间的通信
dest实现bm协程之前的通信
注意到一般是发起通信者去关闭通道
图中的实现是能够保证顺序性的,是并发安全的。使用带缓冲的队列是因为生产者的逻辑比较简单,会比消费者快。这样就不会因为消费者的速度慢影响生产者的执行效率
通过共享内存实现通信,存在多个goroutine同时操作一块内存资源的情况
如果没有加锁,最后数字不是10000,即有并发问题。
注意上面的代码打印x的时候要先sleep一下
使用waitgroup实现并发任务的同步。每完成一个并发任务让计数器-1
当计数器为0时,wait才会解除阻塞
目前为止go module是普遍使用的
因为一个依赖在src里只有一个版本
归根结底 go vender也是在依赖源码,并不能很好的标识版本的概念
这个相当于在一个项目中指定了某个依赖的唯一版本。但是可能出现不同的依赖又依赖于同一个依赖的不同版本。这就出现了问题
module path就是对应的第一行那个module… 后面跟上版本号就能唯一确定指定包的指定版本或者某一个commit
每次commit go都会帮我们生成一个伪版本号
上图的第二条规则就是因为一些项目比较早,当时还有go mod 因此命名无法遵循第一条规则。为了引入这些早期项目,添加了一个+incompatible 这个词的意思是不兼容的。相当于做一个标识表明可能会出现一些不兼容的代码逻辑
go会选择满足本次构建的最低版本,1.3 1.4本身处于同一个大版本下,理应兼容。
如果c此时已经更新到1.5版本,go也不会去选1.5而是选1.4。这就是选择最低的兼容版本
依赖可以从github这样的代码托管平台下。但有缺陷(如图),比如github的作者把某个软件仓库删了,就可能造成之前写好的代码找不到依赖
go proxy会对依赖进行稳定的缓存。保证依赖的稳定性,实现稳定可靠的依赖分发。类似于java中maven的中央仓库。相当于一种适配器的思想,上层解决不了下层的需求,就多加一层
go通过环境变量来控制go proxy
命名正确就会有一个可以运行的标志
使用开源的assert包来进行判断
加上--cover参数就能在测试的同时打印覆盖率
幂等:重复运行一个case的时候与之前的结果应该是要一样的
稳定性:单元测试是相互隔离的,每个测试都可以独立运行
为了避免测试对真正的数据源产生影响,可以使用mock
打桩就是以一个打桩函数去替换原函数
targe就是要被替换的函数,
unpatch就是为了保证在测试结束后把桩卸载掉
底层实现就是在运行时通过go的unsafe包将函数地址替换成打桩函数地址。最终运行了打桩函数
最终实现了mock
函数地址替换,相当于以后执行ReadFirstLine就会执行后面那个函数,不再执行原来的函数