Go语言工程实践笔记|青训营

76 阅读3分钟

并发 VS 并行

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

    并行:多线程程序在多个核的cpu上运行 (实现并发的一个手段)

  • Go可以充分发挥多核优势,高效运行

协程 VS 线程

  • 线程:内核态,线程跑多个协程,创建、切换、停止属于很重的系统操作,栈MB级别 (可以创建上万点协程)

  • 协程:用户态,轻量级线程,栈KB级别

  • 协程之间通信:go提倡通过通信共享内存

    channel:从一个goroutine发送数据到另一个goroutine的数据传输机制。遵循先入先出,保证数据收发到顺序

  • 通过共享内存实现通信:需要获取临界区的权限(加锁),可能会影响性能(go也可以)

Channel

使用 make(chan 元素类型,[缓冲大小])

  • channel可以为无缓冲通道或有缓冲通道
  • 无缓冲通道:也被称为同步通道
  • 有缓冲通道:通道大小代表通道中能存放多少元素,超出会阻塞发送
  • Why using defer close()

并发安全Lock

  • 使用 lock sync.Mutex, lock.Lock() 和 lock.Unlock()进行获取和释放临界区权限

WaitGroup

  • 子协程确切的执行时间未知 ➡️ 无法设置准确的sleep时间

  • 在go中可以使用WaitGroup来实现并发任务的同步,内部维护一个计数器

    Add(delta int):计数器+delta

    Done():计数器 - 1

    Wait():阻塞直到计数器为0

  • 开启协程 + 1

    执行结束 - 1

    主协程阻塞知道计数器为0

依赖管理

  • Go Module现在广为应用

  • 不同环境依赖的版本不同,控制以来库的版本

  • GOPATH是环境变量,go项目的工作区

    bin:项目编译的二进制文件

    pkg:项目编译的中间产物,加速编译

    src:项目源码

    项目代码直接依赖src下的代码,通过go get下载最新版本的包到src目录下

    弊端:A和B依赖于某一package的不同版本,无法实现package的多版本控制。

  • GO Vendor

    项目目录下增加vendor文件,所有依赖包以副本形式放在$ProjectRoot/vendor,解决了多个项目需要同一个package依赖冲突的问题。

    依赖寻址: vendor ⇒ GOPATH

    弊端:无法控制依赖的版本,更新项目有可能出现依赖冲突,导致编译出错。还是依赖源码,而非依赖版本。

  • Go Module

    通过go.mod文件管理依赖包版本,通过go get/ go mod指令工具管理依赖包,实现定义版本规则和管理项目依赖关系

  • 依赖管理三要素

    1. 配置文件,描述依赖 ⇒ go.mod
    2. 中心仓库管理依赖库 ⇒ Proxy
    3. 本地工具 ⇒ go get/mod
  • 在编译时选择最低的兼容版本,v1.3/v1.4 ⇒ v1.4

单元测试

  • 规则

    1. 所有测试文件以_test.go结尾
    2. func TestXxx(*testing.T)
    3. 初始化逻辑放到TestMain中,包括测试前的数据装载、配置初始化等前置工作,以及测试后释放资源等收尾工作
  • 一般覆盖率50%~60%,较高80%

  • 测试分支相互独立、全面覆盖

  • 测试单元粒度足够小,函数单一职责。

  • 依赖

    • 单元测试会依赖如File, DB, Cache等外部依赖。
    • 幂等:重复运行同一个测试结果都相同
  • Mock机制

    • monkey:mock工具
    • 可以实现不依赖本地文件

基准测试

  • 优化代码,需要对当前代码分析
  • 内置的测试框架提供了基准测试的能力

分层结构模型

  • 数据层:数据Model,外部数据的增删改查
  • 逻辑层:业务Entity,处理核心业务逻辑输出
  • 视图层:视图view,处理和外部的交互逻辑