GO语言初探 | 青训营笔记

132 阅读3分钟

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

语言进阶-并发编程

  • 并发-并行——go充分利用多核优势(系统对外的特征)

    • 并发:多线程程序在一个核cpu运行
    • 并行:多线程程序在多个核cpu运行
  • 协程 Goroutine

    • 协程:用户态,轻量级线程,栈MB级别
    • 线程:内核态,线程跑多个协程,栈KB级别
    • 只需要在项目里面加上go func(){}(传入参数) 就是一个协程
    go func(j int) {
       defer wg.Done()
       hello(j)
    }(i)
    
    time.sleep(time.Second) //保存子线程执行完之前主线程不会退出,暴力做法
    
  • CSP(Communicating Sequential Processes)协程通信

    • 通过通信共享内存而不是通过共享内存实现通信(通道)
  • 通道 Channel

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

      • 无缓冲通道 make(chan int)
      • 有缓冲通道 make(chan int,2)
func CalSquare() {
   src := make(chan int)
   dest := make(chan int, 3)  //有缓冲通道,消费者消费速度会比打印更复杂,所以可能会慢一些,用带缓冲队列就不会因为消费者速度问题影响生产效率
   go func() {      //A协程发送0-9数字
      defer close(src)  //延迟资源关闭
      for i := 0; i < 10; i++ {
         src <- i
      }
   }()
   go func() {     //B协程计算输入数字的平方
      defer close(dest)
      for i := range src {
         dest <- i * i  
      }
   }()
   for i := range dest {  //main协程打印输出
//复杂操作 
      println(i)
   }
}

依赖管理

管理依赖库

  • Gopath

    • go语言配置的环境变量

      • bin二进制文件、pkg中间产物、src源码
    • 无法实现package的多版本控制(不同的项目调用不同版本的包冲突)

  • Go Vendor

    • vendor 解释了详细的依赖包,每个项目分开在vender目录下寻找依赖(解决版本冲突)
    • 无法控制依赖版本
    • 更新项目可能出现依赖冲突,导致编译出错
  • Go Module : go.dev/blog/using-…

    • go.mod文件管理依赖包版本
    • go get/go mod 指令工具管理依赖包
    • 定义版本规则和管理项目依赖关系
  • 依赖管理三要素

    1. 配置文件,描述依赖 go. mod
    2. 中心仓库管理依赖库 Proxy
    3. 本地工具 go get/mod
  • go会选择最低的兼容版本(所有依赖中的最新版本、向下兼容)

  • 依赖分发

    • GOPROCY="<https://proxy1.cn>,<https://proxy2.cn>,direct"
    • 服务站点url列表,“direct代表源站”
  • 工具——go get example.org/pkg

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

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

了解 Go 依赖管理演进的历程,通过课程学习以及课后实践能能够熟练使用 go module 管理依赖。

单元测试

  • 单元测试

    • 概念和规则:go.dev/doc/tutoria… pkg.go.dev/testing

    • 单元测试-集成测试-回归测试(从上到下覆盖率逐层变大,成本逐层降低)

    • 单元测试组成

      • 输入
      • 测试单元(函数、模块)
      • 输出
    • 优点

      • 保证质量
      • 提升效率(定位问题、防止损失扩大化)
    • 规则

      • _test.go结尾
      • func TestXxx(*testing.T)
      • 初始化逻辑在TestMain中
    • 覆盖率:判断单元测试有效性


func TestManyGo(t *testing.T) {
			//测试前:数据装载、配置初始化
      ManyGo()
			//测试后、释放资源等收尾工作
}
  • Mock 测试

  • 基准测试

    • pkg.go.dev/testing#hdr…

    • 随机对函数执行基准测试

    • 优点

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

项目实战

需求模型来源

青训营话题页forum.juejin.cn/youthcamp/p…

需求

  1. 实现一个展示话题(标题,文字描述)和回帖列表的后端 http 接口;
  2. 本地文件存储数据

组件及技术点

代码:repository-index

初始化话题数据索引

package repository

import (
   "bufio"
   "encoding/json"
   "os"
)

var (
   topicIndexMap map[int64]*Topic
   postIndexMap  map[int64][]*Post
)

func initTopicIndexMap(filePath string) error {
   open, err := os.Open(filePath + "topic") //打开文件
   if err != nil {
      return err
   }
   scanner := bufio.NewScanner(open)
   topicTmpMap := make(map[int64]*Topic) //迭代器对数据遍历刻入结构体产生索引
   for scanner.Scan() {
      text := scanner.Text()
      var topic Topic
      if err := json.Unmarshal([]byte(text), &topic); err != nil {
         return err
      }
      topicTmpMap[topic.Id] = &topic
   }
   topicIndexMap = topicTmpMap
   return nil
}