这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天.
1.Go语言的并发与并行
- 多线程程序在一个核的CPU上运行,如下图:
- 多线程程序在多个核的CPU上运行
Go语言可以充分发挥多核优势,高效运行。Go语言实现计算机调度模型,完成高并发能力。
**1.1 Goroutine
Go语言的协程开启只需要在函数面前加关键字go,源代码如下:
package main
import (
"fmt"
"time"
)
func hello(i int) {
fmt.Println("hello gorouine: " + fmt.Sprint(i))
}
func HelloGoRoutine() {
for i := 0; i < 5; i++ {
go func(j int) { //go语言创建协程:在函数前加go关键字
hello(j)
}(i)
}
time.Sleep(time.Second)
}
func main() {
HelloGoRoutine()
}
最终效果如下:
**1.2 Channel
go语言通过通信而共享内存,而不是通过共享内存实现通信。
使用make(chan元素类型,[缓冲大小]),例如有缓冲通道make(chan int),无缓冲通道make(chan int,2)
源代码如下:
func CalSquare() {
src := make(chan int)
dest := make(chan int, 3) //有缓冲的通道
//子协程A生成数字
go func() {
defer close(src) //defer关闭通道
for i := 0; i < 10; i++ {
src <- i
}
}()
//子协程B计算平方
go func() {
defer close(dest)
for i := range src {
dest <- i * i
}
}()
//主协程打印结果
for i := range dest {
println(i)
}
}
实验结果:
**1.3并发安全-lock函数保证数据安全
**1.4 Sync-WaitGroup
*Sleep做延迟
*WaitGroup计数器也可以做延迟:开启协程Add()+1;执行结束Done()方法-1;主协程阻塞直到计数器为0.
2.依赖管理
**2.1Go依赖管理演进
GOPATH(无法实现包的多版本控制) -> GO Vendor(可能出现依赖冲突) -> Go Module
Go Module 通过go.mod文件管理依赖包版本;通过go get/go mod指令工具管理依赖包。终极目标是定义版本规则和管理项目依赖关系。
依赖管理三要素包括:go.mod配置文件,描述依赖;Proxy中心仓库管理依赖库;go get/go mod本地工具
**2.2 GoModule依赖管理方案
go module的依赖分发(即从哪里下载)。github是比较常见的代码托管平台,而Go module系统中定义的依赖,最终可以对应到多版本代码管理系统中某一项目的特定提交版本,因此,go.mod对应的依赖可以直接从对应仓库指定软件下载,从而依赖分发。
直接使用版本管理仓库下载依赖,存在多个问题:首先无法保证构建确定性:软件作者可以直接代码平台增加/修改/删除软件版本,导致下次构建使用另外版本的依赖,或者找不到依赖版本;无法保证依赖可用性:依赖软件作者可以直接代码平台删除软件,导致依赖不可用;大幅增加第三方代码托管平台压力。
因此Go Proxy是一个服务站点,可以缓存软件内容,且在源站软件删除后依然可用。
**2.2 GoModule依赖分发-变量GOPROXY
GOPROXY=“proxy1.cn,https://prioxy2.cn…" 服务站点URL列表,优先从Proxy1下载,若不存在,则Proxy2,若还不存在,则直接从源站直接下载(direct控制的)