这是我参与「第三届青训营 -后端场」笔记创作活动的第2篇笔记
1.语言进阶--并发编程
Goroutine通过高效的调度模型,实现协程的高并发操作 Channel提倡通过通信实现共享内存 Sync(lock并发安全操作 wiatgroup实现协程间同步)
并发与并行
并发: 多线程程序在一个核的CPU上运行。 单核CPU中,为了实现多个程序同时运行的假象,通常以时间片调度方式,让每个进程每次执行一个时间片,时间片用完就切换下一进程。由于时间片很短,一段时间内就有多个进程执行。
并行: 多线程程序在多个核的CPU上运行 真正的多个程序同时执行,只能在多核CPU上
Goroutine 协程:用户态,轻量级线程,栈KB级别 线程:内核态,线程跑多个协程,栈MB级别
package concurrence
import (
"fmt"
"time"
)
func hello(i int) {
println("hello goroutine : " + fmt.Sprint(i))
}
func HelloGoRoutine() {
for i := 0; i < 5; i++ {
go func(j int) {
hello(j)
}(i)
}
//暴力通过sleep加阻塞,保证协程在执行完之前,主线程不退出
time.Sleep(time.Second)
}
package concurrence
import "testing"
func TestManyGo(t *testing.T) {
HelloGoRoutine()
}
协程之间通信
CSP(Communicating Sequential Processes)通信顺序进程,是一种并发编程模型,通过channel共享内存
go也保存着通过共享内存实现通信的机制,对于通过共享内存实现通信,对于多访问需要实现加锁,会影响到程序性能
channel
是一种引用类型,创建需要通过make关键字
无缓冲通道(同步通道):使得发送的goroutine和接收的goroutine之间同步化
有缓冲通道(生产消费模型):带有缓冲区,可以解决无缓冲通道的同步问题
src实现了A,B协程间的通信,无缓冲通道,保证了顺序性 desc 使用带缓冲的通道是因为消费者的消费速度较慢(打印),减少由于消费者的消费速度,影响到生产者的执行效率
package concurrence
import "fmt"
func CalSquare() {
src := make(chan int)
dest := make(chan int, 3)
//A子协程发送0~9数字
//
go func() {
defer close(src)
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 {
fmt.Println(i)
}
}
保留了共享内存实现通信
package concurrence
import (
"sync"
"time"
)
var (
x int64
lock sync.Mutex
)
func addWithLock() {
for i := 0; i < 2000; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}
func addWithoutLock() {
for i := 0; i < 2000; i++ {
x += 1
}
}
func Add() {
x = 0
for i := 0; i < 5; i++ {
go addWithoutLock()
}
time.Sleep(time.Second)
println("WithoutLock:", x)
x = 0
for i := 0; i < 5; i++ {
go addWithLock()
}
time.Sleep(time.Second)
println("WithLock:", x)
}
func ManyGoWait() {
var wg sync.WaitGroup
wg.Add(5)
for i := 0; i < 5; i++ {
go func(j int) {
defer wg.Done()
hello(j)
}(i)
}
wg.Wait()
}
使用优雅的WaitGroup代替Sleep
计数器:开始协程+1,执行结束-1,主协程阻塞直到计数器为0
2.依赖管理--依赖管理演进路线
Go依赖管理演进路线 Go Module实战
依赖管理三要素 1.配置文件,描述依赖 go.mod 2.中心仓库管理依赖库 Proxy 3.本地工具 go get/mod
GOPATH
弊端
A和B不能同时构建成功
Go Vendor
弊端
Go Module
依赖配置 go.mod
依赖配置 version
版本定义规则
1.语义化版本
MAJOR 可以不兼容 MINOR 通常是增加新功能,需要在MAJOR下保持前后兼容 PATCH 做代码bug的修复
2.基于commit伪版本 版本前缀-时间戳-12位hash校验码
关键字
1.indirect 非直接依赖
2.incompatible
依赖图
答案B 选择最低的兼容版本,保证C1.3和C1.4兼容
依赖分发-回源
表示依赖从哪下载,如何下载
直接从指定仓库下载存在问题
出现Proxy,解决上面的问题,实现了稳定可靠的依赖分发
Proxy配置
direct表示前面的都没有的话,会回源到第三方代码平台
go mod工具 go get go mod
go get
go mod
3.测试--单元测试
单元测试 Mock测试 基准测试
单元测试组成部分
编写规则
assert
评估单元测试-代码覆盖率
由于外界依赖可能导致测试不稳定->推出Mock技术
基准测试 对代码性能进行测试
4.项目实战--项目需求,需求拆解,逻辑设计,代码实现
项目拆解
代码设计
测试运行
需求用例
E-R图
Topic和Post 一对多的关系
分层结构
组件工具
go get gopkg.in/gin-gonic/gin.v1@v1.3.0
sync.Once 在高并发场景下只执行一次,单例模式
没有前后依赖,可以考虑用并行提高执行效率
通过gin搭建整个web框架