课程笔记二 Go语言进阶 | 青训营笔记

52 阅读1分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

依旧是不长的课程看半天呢 >.<

本节课主要关于工程应用的部分,主要是多协程与版本依赖问题

课程笔记二 Go语言进阶

语句入门

Goroutine(协程)

并行与并发

Go语言可以充分发挥多核计算机的优势,高效运行

线程与协程

1673873378468.png

这是课程中关于线程与协程的图。线程比较消耗资源,协程更加轻量,由go语言进行操作,可以并发的跑多个协程

但图中有错误,协程应该是栈KB级别,线程为栈MB级别

go语言中开启协程

只需简单的在函数调用前加一个go,便可以开启协程的运行,具体例子可以看以下内容

CSP(Communicating Aequential Processes)

GO语言推荐协程之间通过通信而共享内存,而不是通过共享内存而实现通信,以下为课程图

1673874284274.png 虽然go语言依旧支持通过共享内存来实现通信的机制,但是具有并发安全性问题,因为共享内容的原因,有可能存在几个协程同时对内存进行操作的问题。

Channel

channel是一种引用类型,通过make创建

make(chan 元素类型,[缓冲大小])

特别的在此处会用到一个操作符<-,比如 ch <- v发送值v到channel ch中 x := <-ch从channel ch中接收数据并赋值给v

不写缓冲大小即为无缓冲通道(也称为同步通道)

这里的缓存通道类似于一个待处理内容的存放区

defer close(sec)做了一个延迟的资源关闭

func CalSquare(){
    src := make(chan int)
    dest := make(chan int, 3)
    go func() { //该协程发送0-9
        defer close(sec)
        for i:= 0; i<10; i++ {
            src <- i
        }
    }()
    go func() { //该协程计算输入数字的平方
        defer close(dest)
        for i:= 0; i<10; i++ {
            dest <- i
        }
    }()
    for i := range dest {
        输出
    }

并发安全Lock

func addWithlock(){
    for i := 0; i<2000; i++ {
        lock.Lock()  //锁
        x += 1
        lock.Unlock  //解锁
    }
}
func addWithoutLock(){
    for i:= 0; i<2000; i++ {
        x+=1
    }
}
for i := 0; i < 5; i++ {
    go addWithlock() //开启协程
}
未加锁的部分同理

以上中为加锁的最终运行为10000

而未加锁的输出结果位置,结果可能小于10000,出现问题,如上所说的并发安全问题

应避免该情况出现,这也是前面通信再共享内存的原因

WaitGroup

image.png 计数器为0时表示所有任务完成,个人认为是可以高效顺承接下去部分代码的运行,而不用设置固定的sleep时间,提高性能。

依赖管理

工程项目相对复杂,不适合基于标准库从零开始编程,因此需要依赖包

go的依赖管理经过了三个阶段

graph TD
GOPATH  --> Vendor --> Module

GOPATH --> Go Vendor --> Go Module

不同项目以来的版本或许不同,因此对于依赖版本的控制就相当重要

GOPATH

项目代码直接依赖src下的代码

1673878495902.png 很明显存在一个弊端,无法实现package的多版本控制。

Go Vendor

image.png 每个项目引入一个依赖的副本在vendor文件下,先寻址vender,若没有再寻址GOPATH,

解决了多个项目依赖同一个package的多版本问题,但可能会出现不同的package版本不兼容的问题

Go Module

通过go.mod文件管理依赖包版本 通过go get/go mod指令管理工具 1.11引入 1.16以后默认开启

依赖分发问题

若是直接使用版本仓库下载依赖会有问题,由于版本仓库软件作者会对软件版本进行改动,甚至时删除,并且作为一个存放的仓库,会增添第三方的压力

Proxy

Proxy作为一个服务站点,会缓存原站中的内容并不会改变,

从proxy拉取依赖,而proxy从各仓库缓存,保证了依赖的稳定性

Go mod/get (管理工具

Go mod init 初始化,项目的开始

Go mod download 下载模块到软件缓存

Go mod tidy 增加需要的依赖,删除不需要的依赖

关于后面的实践项目, 打算另外写一篇实践篇的笔记, 还需要酝酿>.<