这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天。今天依旧是通过过往的编程经验,来对比go,从而更快掌握。过程中提出问题,便于更深入了解。
概要
- 并发编程(语言方面)
- 依赖管理(项目方面管理第三方包)
语言进阶(高并发)
并发or并行
狭义的并发指分频,并行指多核并行。广义上并行是并发的一种。
go语言通过高效的调度模型,发挥多核优势。(并发or并行?)
协程and线程
协程是用户态,线程是内核态;线程跑多个协程;线程栈MB,协程KB(这是老师讲的,究竟哪个是轻量级,和进程是哪种层级区分,PPT标注错误,MB和KB反过来);go可跑上万个协程
协程
快速:多协程,在调用函数时,加一个协程关键字go,创建一个协程运行该函数(并行)
子协程运行完前,主协程不退出。可先用time.Sleep(time.Second)
协程通信(通信与内存)
通过通信,共享内存 而不是通过共享内存实现通信。
通道(消息传递)和临界区(内存加锁)的区别。通道Channel,先进先出。
通道
make(chan int) make(chan int,2)
无缓冲通道(同步通道)和有缓冲通道(容量,存在通道阻塞)
问题:为什么13:32,能保证顺序性,就指协程安全,这里只能说明先进先出,并不能说明不同协程中,谁先进通道。从理论上来说,channel的先进先出。
- 该时刻的例子真正有意思的在于,for range 在多协程的情况下,保证了channel全部输出,不重复。
带缓冲的队列,好处是,进出不均衡时,不影响效率。进:生产,出:消费。
问题:那无缓冲的通道,进大于出,会出现什么情况,阻塞吗,还是丢失?
临界区(保留的传统方式)
是否使用 锁 会影响结果。并发安全LOCK。
问题:对一个数加2000次这种,使用通道,是否会并发安全,这种情况下,并发的本质,是不是还是排序。
- 这个角度上,是安全的,毕竟非读,只入,非顺序,不用在意中间态。本质上,其实类似锁。
协程阻塞
使用固定时间的time.Sleep(time.Second) 是一种浪费,不如用waitGroup。类似其他语言(如shell)里面的wait与sleep的区别。go的waitGroup,提供Add +delta(在总数上加),Done -1, Wait 阻塞至0,计数器的方式,进行阻塞,类似于Linux多线程编程时,封装的线程锁。
依赖管理
除标准库,第三方包和库的管理,避免造轮子。
框架、日志、集合等,通过SDK
- Gopath
- Go Vendor
- Go Module
不同项目依赖的版本不同,控制依赖库的版本。(是否类似于maven 、 pom)(和python版本管理的区别在哪,会不会也出现不同版本相互之间版本兼容问题)
GOPATH
- bin 最终二进制文件
- pkg 便于加速编译的中间产物
- src 项目源码
项目代码直接依赖src下的代码,把包用 go get 直接下到src里面。
弊端:A和B项目同时依赖某一package的不同版本,版本不兼容时,无法多版本控制,只能实现一个。(是类似java中maven的统一仓库一样,但没法管理,多版本共存吗)
Go Vendor
每个项目单独存放包的副本,解决多个项目版本冲突问题。但依赖的依赖,无法控制。(类似于前端的nodemodules,但不全放)
Go Module
通过go.mod文件管理依赖包,通过 go get / go mod 指令工具管理项目依赖**(与maven和pom文件十分类似)**
go.mod描述依赖,Proxy中心仓库管理依赖库,go get/mod 作为本地工具
go.mod 类似 pom
依赖配置-version
语义化版本 V{MINOR}.${PATCH} major间代码不兼容,隔离。MINOR保证同一major兼容的情况下,加了函数或特性。PATCH做代码BUG修复。
基于commit的伪版本
indirect 间接依赖 , incompatible 标识可能存在的不兼容
依赖配置-依赖图
A和B依赖了不同的C版本,在存在兼容的情况下,会选择一个满足兼容的最低版本
依赖分发-回源
Github、SVN ——> Proxy ——> Developer
Proxy保证依赖稳定性。
依赖分发-变量GOPROXY
工具-go get
依赖管理 下载拉取指定条件的包 (针对包)
工具-go mod
init download tidy (针对项目)