Go语言进阶
这是我参与【第五届青训营】伴学笔记创作活动的第二天,此篇概述一下在青训营学习的go语言的部分进阶知识点。
-
并发 vs 并行
-
go 可以充分发挥多核优势,高效运行
-
go 语言采用协程(goroutine), 一个线程跑多个协程,相比于线程占用更少的运行空间 ,提高了并发性
-
// 简单的开启协程的方法 (直接用go) func hello(j int) { fmt.Println("hello goroutine ", j) } func HelloGoRoutine() { for i := 0; i < 5; i++ { go func(j int){ hello(j) }(i) } time.Sleep(time.Second) }运行结果:
-
-
通道的使用
-
提倡通信共享内存而不是通过共享内存而实现通信,采用了 channel
-
Channel 的使用方法
make(chan type, [缓冲大小])
- 无缓冲通道:make(chan int) (同步通道)
- 有缓冲通道:make(chan int, 2) (阻塞+运行)
-
简单应用
func CalSquare() { src := make(chan int) dest := make(chan int,3) // 生产数字 go func() { defer close(src) for i := 0; i < 10; i++ { src <- i // 生产i } } // 消费数字 go func() { defer close(dest) for i :=range src { dest <- i * i // 消费i,记录i*i } }() // 输出结果 for i := range dest { println(i) } }
-
-
并发安全 Lock
-
简单加锁的方法:
var ( x int64 lock sync.Mutex ) func addWithOutLock() { for i := 0; i < 2000; i++ { x += 1 } } func main() { x = 0 for i := 0; i < 5; i++ { go addWithOutLock() } time.Sleep(time.Second) fmt.Println(x) }结果分析:未加锁时,由于五个协程并行的原因,可能当一个协程读取原来的x, 而另一个协程已经将原来的 x 加 1,即原来的 x 发生改变,此时第一个进程加1后写入,覆盖掉了第二个进程的加1操作,即出现 x 的大小小于 10000
-
WaitGroup 优化
func MangGowait() { var wg sync.WaitGroup wg.Add(5) // 计数器增加 5 for i := 0; i < 5; i++ { go func(j int) { defer wg.Done() // 计数器减 1 hello(j) }(i) } wg.Wait() // 等待结束 }
-
-
依赖管理
-
作用:定义版本规则和管理项目依赖关系
-
go 依赖管理推进:gopath -> go vendor -> go module
-
依赖管理三要素:
- 配置文件,描述依赖: go.mod
- 中心仓库管理依赖: Proxy
- 本地工具 : go get / mod
-
version:语义化版本/ 基于commit 伪版本
-
indirect 非直接依赖
-
选择兼容低版本
-
-
依赖分发
图一为回源,图二为proxy
采用 Proxy 的优点:稳定,可靠,缓解压力
-
go get 与 go mod
go get example.org/pkg @update // 默认 @none // 去除依赖 @v1.1.2 // 语义版本 @23dfdd5 // 特定的commit @master // 分支的最新的commit go mod init // 初始化,创建 go.mod文件 download // 下载模块到本地缓存 tidy // 增加需要的依赖,去除不需要的依赖