这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
一、本堂课重点内容:
语言进阶
依赖管理
测试
项目实战
二、语言进阶
并发与并行
并发:多线程程序在一个核的CPU上运行
并行:多线程程序在多个核的CPU上运行
Go可以充分发挥多核优势 高效运行
线程与协程
协程:用户态,轻量级线程,栈MB级别。线程:内核态,线程跑多个协程,栈KB级别。
在调用函数时在前面加上go即可开启一个携程
提倡通过通信共享内存而不是通过共享内存而实现通信
channel
如果说goroutine是Go语言程序的并发体的话,那么channels则是它们之间的通信机制。一个channel是一个通信机制,它可以让一个goroutine通过它给另一个goroutine发送值信息。
无缓冲通道会使发送的gorountine和接收的gorountine同步化。(也叫同步通道)
一个channel有发送和接受两个主要操作,都是通信行为。一个发送语句将一个值从一个goroutine通过channel发送到另一个执行接收操作的goroutine。发送和接收两个操作都使用<-运算符。在发送语句中,<-运算符分割channel和要发送的值。在接收语句中,<-运算符写在channel对象之前。一个不使用接收结果的接收操作也是合法的。
Sync
若采用共享内存实现通信,则会出现多个Goroutine同时操作一块内存资源的情况。为了保证多个线程或者 goroutine在访问同一片内存时不会出现混乱,使用sync.Mutex进行加锁。 sync.Mutex允许在共享资源上互斥访问(不能同时访问):
mutex := &sync.Mutex{}
mutex.Lock()
// Update共享变量 (比如切片,结构体指针等)
mutex.Unlock()
三 依赖管理
3.1 GOPATH
bin 项目编译的二进制文件
pkg项目编译的中间产物,加速编泽
src项目源码
go get下载最新的包到src目录下
3.2 go Vendor
在Vendor机制下,如果当前项目存在Vendor目录,会优先使用该目录下的依赖,如果依赖不存在,会从GOPATH中寻找; 但vendor无法很好解决依赖包的版本变动
例如项目A依赖pkg b和c,而B和C依赖了D的不同版本,通过vendor的管理模式我们不能很好的控制对于D的依赖版本。归根到底vendor不能很清晰的标识依赖的版本概念。下面, go module就应运而生了。
3.3 Go Moudle
通过go.mod文件管理依赖包版本 通过go get/go mod指令工具管理依赖包
3.4依赖配置
Version
语义化版本: {MINOR}.${PATCH} 例如:V1.3.0 V2.3.0
基于commit伪版本: vx.0.0-yyymmddhhmmss abcdefgh1234
indirect/incompatible
indirect后缀,表示go.mod对应的当前模块,没有直接导入该依赖模块的包,也就是非直接依赖,标示间接依赖,
下一个常见是的是incompatible,主版本2+模块会在模块路径增加/N后缀, 这能让go module按照不同的模块来处理同一个项目不同主版本的依赖。由于gomodule是1版本。 实验性引入这项规则提出之前已经有一些仓库打上了2或者更高版本的tag了,为了兼容这部分仓库,对于没有go.mod文件并且主版本在2或者以上的依赖,会在版本号后加上+incompatible后缀
中心仓库管理依赖库
github是比较常见给的代码托管系统平台,而Go Modules系统中定义的依赖,最终可以对应到多版本代码管理系统中某-项目的特定提交或版本,这样的话,对于go.mod中定 义的依赖,则直接可以从对应仓库中下载指定软件依赖,从而完成依赖分发
但直接使用版本管理仓库下载依赖,存在多个问题。
首先无法保证构建确定性:软件作者可以直接代码平台增加/修改/删除软件版本,导致下次构建使用另外版本的依赖,或者找不到依赖版本。
无法保证依赖可用性:依赖软件作者可以直接代码平台删除软件,导致依赖不可用;
大幅增加第三方代码托管平台压力。
而go proxy就是解决这些问题的方案,Go Proxy是一一个服务站点, 它会缓源站中的软件内容,缓存的软件版本不会改变,并且在源站软件删除之后依然可用,从而实现了供immutability和"available"的依赖分发;使用Go Proxy之后,构建时会直接从Go Proxy站点拉取依赖。
go get/mod
小结
今日整理了工程进阶和依赖管理的相关内容,对一些平时知道怎么用但不清楚原理的知识加深了理解,例如goproxy和indierct后缀。