这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
1 语言进阶
1.1 并发和并行
并发(concurrency):把任务在不同的时间点交给处理器进行处理。在同一时间点,任务并不会同时运行。
并行(parallelism):把每一个任务分配给每一个处理器独立完成。在同一时间点,任务一定是同时运行。 并发不是并行。并行是让不同的代码片段同时在不同的物理处理器上执行。
GO可以充分发挥多核的优势,高效运行。
1.1.2 Gorutine
协程:用户态,轻量级的线程,栈kb级别,由go语言调用,go语言一次可以跑上万的协程。
线程:内核态,线程可以跑多个协程,栈mb级别
1.1.2.1协程的使用
非常简单,在函数前加go关键字就可以。
func f(){
fmt.println("hello,world!")
}
func main(){
go f()
}
1.1.2.2协程的通信
两种方法,一种是通过通道实现通信,另一种是共享内存实现通信(必须使用互斥量,对内存进行加锁,保证数据访问的安全性,不同的gorutine之间会发生冲突)
Channel的创建
// make(chan 元素类型,[缓冲大小])
make (chan int,2) // 有缓冲通道
make (chan int) // 无缓冲通道 (todo:不知道这个的作用是啥,视频没有讲清楚)
- 无缓冲的通道必须有一个接收的协程,否则发送方将一直阻塞。
channel应仅由发送方执行,而不应由接收方执行,并且在收到最后发送的值后具有关闭通道的效果。- for循环可以遍历通道,直到通道关闭,理解的是,关闭后不再动态监听通道,而是遍历完当前通道内已有的元素。
共享内存区
必须对内存区的数据加锁,就是对于所有协程可以访问的数据结构要加锁
package main
import (
"fmt"
"sync"
"time"
)
var (
x int64
lock sync.Mutex
)
func addWithLock() {
for i := 0; i < 2000; i++ {
lock.Lock()
x = x + 1
lock.Unlock()
}
}
func addWithoutLock() {
for i := 0; i < 2000; i++ {
x = x + 1
}
}
func add() {
for i := 0; i < 5; i++ {
go addWithLock()
}
time.Sleep(time.Second)
fmt.Println(x)
for i := 0; i < 5; i++ {
go addWithoutLock()
}
time.Sleep(time.Second)
fmt.Println(x)
}
func main() {
add()
}
加锁了可以加到10000,没有加锁的这个对临界区没有保护,结果无法追踪。
WaitGroup
主要目的是让主函数阻塞直到子协程执行完毕。
有一个写代码的方法,包装一个内部函数,在该内部函数里调用真正需要执行的函数和WaitGroup的Done方法,这样当功能函数执行完毕后,会调用WaitGroup的Done方法。
func hello(n int) {
fmt.Printf("hello world %d\n", n)
}
func goWaitGroup() {
var wg sync.WaitGroup
wg.Add(4)
for i := 0; i < 4; i++ {
go func(j int) {
defer wg.Done()
hello(j)
}(i)
}
wg.Wait()
}
2 依赖管理
2.1 最早的gopath
gopath下有三个目录,bin,pkg,src三个目录,项目的代码直接依赖src下的代码,go get下载的新版本的包也放到src目录下。
弊端
多个项目依赖于package的不同版本,无法实现package的多版本控制
2.2 Go Vendor
就是在项目的目录下增加一个vendor文件夹,所有依赖包副本形式都放在vendor下,依赖寻址的方式优先寻找vendor,找不到再去找gopath下, 这样就解决了多版本控制的问题。
弊端
他仍然是依赖的源代码,而不能标识依赖的版本
2.3 Go Module
通过go.mod文件管理依赖包版本
2.3.1 依赖管理的三要素:
- 配置文件:go.mod
- 中心仓库管理依赖库:Proxy
- 本地工具:go get/mod
2.3.2 go的设置
GOPROXY
代理配置,direct表示源站
GO111MODUL
GO111MODULE有三个值:off、on 和 auto(默认值)
GO111MODULE=off,无模块支持,go 会从 GOPATH 和 vendor 文件夹寻找包
GO111MODULE=on,模块支持,go 会忽略 GOPATH 和 vendor 文件夹,只根据 go.mod 下载依赖
GO111MODULE=auto,在 $GOPATH/src 外面且根目录有 go.mod 文件时,开启模块支持
2.3.3 go.mod详解
zhuanlan.zhihu.com/p/413040181
大版本号,表示兼容性,小版本号表示更新,最后的版本号表示bug修复。
2.4 依赖分发
最常见的是github
直接使用GitHub的依赖会有一些问题:
- 无法保证构建的稳定性,依赖软件会进行赠更改版本
- 无法保证依赖的可用性,可能删掉依赖
- 第三方平台的压力很大
为了解决上述问题,出现了一个proxy代理。这个proxy会更稳定,一般使用proxy进行依赖拉取。 (遇到设计的问题时,没有问题是proxy无法解决的,如果解决不了就建立两层proxy)
3 测试
todo
4 项目实战
todo