D2:「Go 语言上手 - 工程实践」| 青训营笔记

104 阅读1分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记

1、语言进阶

并发与并行
线程与协程
  • 线程

    • 属于内核态,线程跑多个协程
    • 创建、切换、停止都属于很重的系统操作
    • 协程并发
  • 协程(Gorountine)

    • 用户态,轻量级线程
协程通信
  • go提倡通过通信共享内存

    • 通过通道让一个Gorountine发送消息到另一个
  • 通过共享内存而实现通信

    • 通过互斥量对内存加锁
    • 不同Gorountine在一定程度上影响性能
  • 代码案例

    • 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)
         }
         time.Sleep(time.Second)
      }
      ​
      func main() {
         HelloGoRoutine()
      }
      
Channel
  • make

    • 无缓冲通道(make(chan int))

      • 同步通道
      • 发送和接收同步化
    • 有缓冲通道(make(chan int, 2))

      • 生产消费模型,缓冲通道类似货架
  • 实现并发编程安全和协程间的同步

  • 代码案例

    • package main
      ​
      func CalSquare() {
         src := make(chan int)
         dest := make(chan int, 3)
         go func() {
            defer close(src)
            for i := 0; i < 10; i++ {
               src <- i
            }
         }()
         go func() {
            defer close(dest)
            for i := range src {
               dest <- i * i
            }
         }()
         for i := range dest {
            println(i)
         }
      }
      ​
      func main() {
         CalSquare()
      }
      
sync.WaitGroup
  • wg.Add(5) //开启5个协程

  • wg.Done() //计数器-1 表明子协程结束

  • wg.Wait()

  • 代码案例

    • package main
      ​
      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) //9136
         x = 0
         for i := 0; i < 5; i++ {
            go addWithLock()
         }
         time.Sleep(time.Second)
         println("WithLock:", x) //10000
      }
      ​
      func main() {
         Add()
      }
      

2、依赖管理

GoPath环境变量
  • bin

    • 项目编译的二进制文件
  • pkg

    • 项目编译的中间产物,加速编译
  • src

    • 项目源码
  • 项目代码直接依赖src下的代码

  • go get 下载最新版本的包到src目录下

  • 无法实现package的多版本控制

Go Vendor
  • 项目目录下增加vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor
  • 依赖寻址方式:vendor=>GOPATH
Go Module
  • 通过go.mod文件管理依赖包版本
  • 通过go get/go mod指令工具管理依赖包
  • 终极目标:定义版本规则和管理项目依赖关系
管理依赖三要素
  • 配置文件,描述依赖

    • go.mod
  • 中心仓库管理依赖库

    • Proxy
  • 本地工具

    • go get/mod
本地工具
  • go get

    • @update 默认
    • @none 删除依赖
    • @v1.1.2 tag版本,语义版本
    • @23dfdd5 特定的commmm
    • @master 分支的最新commit
  • go mod

    • init 初始化,创建go.mod文件
    • download 下载模块到本地缓存
    • tidy 增加需要的依赖,删除不需要依赖

3、测试

回归测试
单元测试
  • 测试目的

    • 保证质量
    • 提升效率
  • 测试规则

    • 以_test.go纪委
    • func TestXxx(*testing.T)
    • 初始化逻辑放到TestMain中
集成测试

4、项目实战

社区话题页面
组件工具
  • GIN

    • 高性能go web框架
  • Go Mod

    • go mod init
    • go get gopkg.in/gin-gonic/gin.v1@v1.3.0