1、语言进阶--并发编程
1.1 Goroutine(协程)
并发与并行
并发:多线程程序在一个核的cpu上的运行
并行:多线程程序在多个核的cpu上运行
而go语言可以充分发挥多核性能,解决高并发问题
线程与协程
线程:内核态,线程跑多个协程,栈MB级
协程:用户态,轻量级线程,栈KB级
如何开启协程
实例:快速打印hello groroutine
go语言开启协程的方法就是在函数名前加一个go
package main
import (
"fmt"
"time"
)
func hello(i int) {
println("hello goroutine : " + fmt.Sprint(i))
}
func closure() {
for i := 0; i < 3; i++ {
go func(j int) {
hello(j)
}(i)
}
time.Sleep(time.Second)
}
func main() {
closure()
}
time.Sleep(time.Second)的作用是暴力阻塞,保证子协程结束前主协程不退出,输出是乱序,可以知道,是并行打印的。
2、依赖管理
在开发时,我们不能所有东西都从0开始,而是更多的使用已经开发测试好,封装好的组件,专注于业务逻辑
GO的依赖管理经历了3个阶段GOPATH -> GO VENDER -> GO MODULE
GO MODULE
GO 1.16默认开启
通过go.mod文件管理依赖包版本
通过go get/go mod指令工具管理依赖包
依赖管理的三要素:
1.配置文件,描述依赖 go.mod
2.中心仓库管理依赖库 Proxy
3.本地工具 go get/mod
类似java中maven对依赖的管理,导入依赖
依赖配置-go.mod
依赖管理基本单元:标识了模块路径
单元依赖由两部分组成:模块路径和版本号
依赖配置-version
1.语义化版本
${MAJOR}.${MINOR}.${PATCH}
MAJOR:大版本,不同MAJOR可以不兼容
MINOR:新增函数与功能,相同MAJOR下的不同MINOR要兼容
PATCH:代码bug修复
如:V1.3.0
2.基于commit伪版本
vx.0.0-yyyymmddhhmmss-abcdefgh1234
中间部分是一个提交的时间戳
后面是一个12位哈希码
依赖配置-indirect
对于没有直接依赖的用indirect标注
依赖配置-incompatible
主版本2+模块会在模块路径增加/N后缀。
对于没有go.mod文件并且主版本2+的依赖,会+incompatible
依赖最低兼容版本选择
如果X项目依赖了A、B两个项目,且A、B分别依赖了C项目的v1.3、v1.4两个版本,最终编译时所使用的C项目的版本为哪个呢?
答案是v1.4,因为go对版本的选择使用最低兼容版本,因为1.3与1.4是兼容的所以会优先选择1.4
这就是依赖最低兼容版本选择
依赖分发-回源
可以直接从github上去下载依赖,但是这样会有几个问题
1.无法保证构建稳定性增加/修改/删除软件版本,作者可以随时修改代码,导致我们本地的代码出现问题
2.无法保证依赖可用性删除软件,作者可能会删除
3.增加第三方压力,代码托管平台负载问题
依赖分发-Proxy
Proxy会缓存一些软件内容,缓存的版本不会改变,通过这个中间站点,保证了代码稳定性
我们可以直接去Proxy去选择一些依赖
依赖分发-变量GOPROXY
通过控制GOPROXY环境变量来控制Proxy配置
GOPROXY="proxy1.cn, proxy2.cn ,direct”
是url列表,direct表示,前两个地方都没有时,会回到源站去
以下是依赖查找路径示意图:
工具1-go get
默认加@update,拉取最新版本
工具2-go mod
每个项目开始前init去初始化创建一个go.mod文件
经过代码的修改,可能有些依赖已经不需要了,可以每次上传代码时进行tidy操作,来更新依赖