这是我参与「第五届青训营 」伴学笔记创作活动的第2天
前言
本文主要从并发编程、依赖管理和项目测试三个方面对go语言进行讲解。
并发编程
1.概念
进程vs线程
进程
简单来说,每一个正在运行的程序就是一个进程。其中,进程既是一个操作系统的基本分配单元,也是操作系统的基本执行单元。 一般进程有三个状态:就绪态、阻塞态和运行态。
线程
线程是进程中执行运算的最小单元,也是操作系统执行处理机制的基本单位。 线程只有一个进程,但进程可以有多个线程。
并发vs并行
并发
多个线程在一个核的cpu上运行,交替运行,不是同时进行,争夺资源。
并行
多个线程在多个核的cpu上运行,多个任务同时执行,不争夺资源。
2.Goroutine
main函数对应主线程,其中主线程里的一个轻量级线程则为协程。
-
线程:内核态,轻量级线程,栈MB级别
-
协程:用户态,线程跑多个协程,栈KB级别
基本代码如下:
下面是并行运行结果,并不是按照顺序运行完成,不同协程的运行时间不同。
3.通信
CSP
go语言的通信过程是通过通信共享内存而不是通过共享内存来实现通信
Channel
用make创建通道进行通信
make(chan int) 无缓冲通道
make(chan int,2) 有缓冲通道
测试证实,有缓冲通道效率更高
3.并发安全
并发必然有安全风险,不同线程可能会对同一块内存空间进行操作而导致内存泄漏等安全问题,因此需要上锁来作为保障。
Lock
教程中有一个直观的例子:
结果中,不加锁的明显比实际结果有差距。当然,多次测试,不加锁的结果可能会发生变化,具有不确定性。 这让我们更加重视加锁的重要性。
WaitGroup
有的协程阻塞时采用延时方法,但实际情况中不知道准确时间,因此我们可以采用WaitGroup的方法。
教程中将之前的代码进行了改进:
这让代码运行更加安全。
依赖管理
go的依赖管理主要历经了三个阶段:GOPATH、Go Vender、Go Module,迭代过程中,依赖管理更加方便,更新代码时减少了很多工作量。
1.GOPATH
go的工作目录下有三个子目录:bin、pkg、src。
-
bin:项目编译的二进制产物
-
pkg:项目编译的中间产物,可以加速编译、
-
src:项目源码`
直接将代码放入src,后进行运行。
但其弊端是无法进行依赖包的多版本控制。
2、Go Vender
之前基础上增加vendor文件,放入依赖包副本。
- 优点:解决了多个项目需要同一个package依赖的冲突问题。
- 缺点:无法控制依赖的版本;更新项目可能出现依赖冲突
3、Go Modul
三要素:
- go.mod 配置文件,描述依赖
- Proxy 中心仓库管理依赖库
- go get/go mod 指令工具管理依赖包
进而定义了版本规则并管理了项目的依赖关系。
Proxy
本地依赖(可以看作一个缓存仓库),进行依赖分发,保证了依赖的稳定性和可用性。
项目测试
常常分为回归测试、集成测试、单元测试,依次覆盖率变大,成本变小。 在日常测试过程中,常常采用单元测试。
1.命名规则
- 测试文件以—test.go结尾
- 函数func Testxxx(* testing.T)
- 初始化在TestMain中
常用工具:assert
测试者与实际比较,教程中案例如下:
2.测试方法
- 覆盖率:要求测试分支相互独立,测试情况全面覆盖源码,覆盖率越高越好
- Mock:为函数或方法打桩,不再依赖本地文件
小结
主要学习了一些go语言内部逻辑,更有利于我们理解go语言的构成,进而为之后编程打下基础。相信有小伙伴跟我一样,之前学习编程主要学习语法,能编程实践就行,而这些语言的构成等理论知识根本不在意。而我在学习后,更发现go语言的巧妙之处,进而引起我对java等语言底层逻辑的兴趣。希望大家在编程之余,还能多了解一下我们常用工具的原理,进而真正学会用会它!
参考
- 字节跳动青训营Go语言进行课程