Go语言day2笔记整理 | 青训营

114 阅读4分钟

day2笔记整理简洁版:)

go语言进阶和依赖管理

协程

并发:多线程在一个核的cpu上运行 并行:多线程在多个核的cpu上运行

Goroutine(协程)
  • 线程:内核态,(昂贵的系统资源)线程跑多个协程,MB级别
  • 协程:用户态,轻量级线程,KB级别

使用协程:在函数前加上go/协程通信CSP image.png

  • 不推荐借助临界区(共享内存)实现通信
  • 推荐使用通信(通道)来共享内存
Channel(通道)

Make(chan 元素内心 int)

  • 无缓冲通道 make (chan int)//同步通道
  • 有缓冲通道 make (chan int,2)//缓冲区大小为2

由于消费者的逻辑可能比生产者复杂,因此在消费者和最终结果之间加上有缓冲的通道,防止其对生产者效率的影响

并发安全Lock(共享内存实现通信)
  • WaitGroup:(代替sleep进行阻塞)实现并发任务的同步(计数器)
  • Add(delta int)//调用多少个并发任务
  • Done()//计数器-1
  • Wait()//阻塞,等待所有并发任务执行结束

依赖管理

不同环境依赖的版本不同

GOPATH(环境变量)
  • Bin//项目编译的二进制文件
  • Pkg//中间产物
  • Src//源码

项目直接依赖src的代码,Go get下载最新版本的包(无法实现多版本控制,只能有一个版本的package)

Go Vendor

项目目录增加一个vendor文件,依赖包副本存放在vendor中(依赖项目源码,不能标识版本的区别)

Go Module
  • 通过go.mod文件管理依赖包版本
  • 通过go get/go mod指令工具管理依赖包

依赖管理三要素

  1. 配置文件,描述依赖 go.mod
  2. 中心仓库管理依赖库 Proxy
  3. 本地工具          go get/mod
Go.mod
module github.com/Moonlight-Zhao/go-project-example

go 1.16

require (
	github.com/gin-contrib/sse v0.1.0 // indirect
	github.com/gin-gonic/gin v1.3.0 // indirect
	github.com/go-playground/validator/v10 v10.10.0 // indirect
	github.com/goccy/go-json v0.9.6 // indirect
	github.com/golang/protobuf v1.5.2 // indirect
	github.com/jinzhu/now v1.1.5 // indirect
	github.com/json-iterator/go v1.1.12 // indirect
	github.com/kr/pretty v0.3.0 // indirect
	github.com/mattn/go-isatty v0.0.14 // indirect
	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
	github.com/rogpeppe/go-internal v1.8.0 // indirect

)
  1. 模块路径(依赖管理基本单元)
  2. 原生库版本号
  3. 单元依赖
Version(版本规则)

语义化版本

  • ${MAJOR}大版本,代码隔离可以不兼容
  • ${MINOR}小版本,前后兼容,包括新增函数和功能。
  • ${PATCH}版本修复
基于commit伪版本

版本前缀-时间戳-哈希码前缀

Indirect关键字

没有直接导入的模块为间接依赖,用indirect标识出来

Incompatible

对于v2以上的依赖,在版本号的后面做标识,当选择多个版本时,选择最低的兼容版本

依赖分发

image.png

Proxy
  1. 缓存软件内容(稳定,可靠)

image.png

GOPROXY(url列表)=“proxy1,proxy2,direct”

image.png

image.png

image.png

测试

单元测试

image.png

单元测试规则
  1. 测试文件以_test.go结尾
  2. Func TestXxx(testing.T)
  3. 初始化逻辑放到TestMain(测试前进行数据装载、配置初始化等前置工作)//测试后进行资源释放等收尾工作
断言:assert
评估测试: 代码覆盖率

Go --cover计算覆盖率

如何提高?

  • 测试分支相互独立、全面覆盖
  • 测试单元粒度足够小,函数单一职责
  1. 依赖(幂等、稳定)(文件可能被篡改或删除,则该函数无法运行)
  2. 幂等:重复做一次case的结果相同
  3. 稳定:单元测试相互隔离
Mock(运行时,将内存中函数地址进行替换)

为一个函数打桩/为一个方法打桩

  • Patch(target//目标函数,replacement//打桩函数)//用打桩函数替换目标函数
  • Unpatch//卸载桩

Mockey的作用是原函数由于调用第三方的内容无法执行时,进行打桩将其替代来测试其他函数的功能。

基准测试(对代码进行性能分析)

Rand的性能在并行时变低(全局锁) Fastrand

项目实践

社区话题页面
  • 展示话题(标题,文字描述)和回帖列表
  • 暂不考虑前端页面实现,仅仅实现一个本地web服务
  • 话题和回帖数据用文件存储

步骤

  1. 定义需求用例
  2. ER图
  3. 分层结构 image.png
  • 数据层:数据model。外部数据的增删改查
  • 逻辑层:业务Entity,处理核心业务逻辑输出
  • 视图层:视图view,处理和外部的交互逻辑
组件工具:

1.Gin高性能go web框架 2.Go Mod

Repsository:

image.png

实现基本查询操作: QueryTopicById     QueryPostsByParentId

借助index索引map快速定位到数据,定义两个map来查找.

  1. 打开文件
  2. 将数据行遍历
  3. 转换为结构体并存储到map中

查询操作:直接给根据id在map中寻找

Service层

定义实体:

type PageInfo struct {
    Topic *repository.Topic
    PostList []*repository.Post
}

image.png PrepareInfo:从Repsository层拿数据(借用两个查询方法) image.png 两者没有相互依赖,可以进行并行.

Controller层
  1. 构建view对象
  2. 业务错误码
Router
  1. 初始化数据索引
  2. 初始化引擎配置
  3. 构建路由
  4. 启动服务