后端go进阶|青训营笔记

109 阅读3分钟

一.go语言为什么这么快:协程、并发

  • go可以充分发挥多核优势,高效运行,那么实现高并发主要原因就是协程。协程比线程轻量。

    1. 线程:属于内核资源,它的变化、操作都是有操作系统控制,而且需要很大的资源,
    2. 协程:属于轻量级的线程,它的调度由go语言本身完成,线程上可以跑多个协程
  • go语言开启一个协程的方法:go+一个函数,相当方便。

    • 例如 go func1()
  • go语言提倡通过通信共享内存,而不是通过共享内存而实现通信。为什么呢?因为通过共享内存通信的话,就避免不了加锁了,对共享的内存进行加锁,这样就影响了go程序的性能。

    1. go中协程之间是通过Channel进行通信,Channel是一个队列,遵循先进先出的原则。、

    2. Channel创建:make(chan type,[缓存大小])

    3. Channel分类:通过是否有缓存大小分为无缓冲通道make(chan int)、有缓冲通道(chan int,2)

      • 区别:使用无缓冲通道**会使发送的gorountine和接收的gorountine同步化,**因此无缓冲通道也被称为同步通道。

        func main() {
           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
              }
           }()
        
           go func() {
              for i := range dest {
                 println(i)
              }
           }()
        
        }
        
  • waitGroup的作用:

    • 当我们开启一个协程后,主线程也还在执行中,那么如果主线程先结束了,协程还没有结束,此时协程也退出,这样导致结果肯定错误。

    • 有什么办法可以解决这个问题呢?

      1. 第一个:不优雅的解决方案,就是在主线程中sleep一段时间,打赌协程在这段时间内就会结束,那么主线程可以等到协程结束后再结束。

      2. 就是使用waitGroup:有三个函数

        1. Add(deleta int),每增加一个协程计数器加一
        2. Done(),每结束一个协程计数器减一
        3. Wait(),阻塞等待计数器为0

        例子:

        func hello(j int){

        fmt.Println(j)

        }

        func main(){

        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()

        }

二.依赖管理

  • go的依赖管理经历了三个过程:GOPATH->GO Vendor->Go Module
    1. GOPATH:是go语言的环境变量,是go项目的工作区,下面有三个包bin、pkg、src,分别存放的文件是项目编译的二进制文件、项目编译的中间产物,加速编译、项目源码。
      • 项目代码直接依赖src下的代码,go get下载最新版本的包到src目录下
      • GOPATH弊端:无法实现package的多版本控制
    2. Go Vendor:项目目录下增加vendor文件,所有依赖包副本形式放在ProjectRoot/vendor。此时寻找依赖的方式是先在verdor下找,如果没有就去GOPATH下找,解决了多个项目需要同一个package依赖冲突问题
      • go vendor问题:无法控制依赖的版本、更新项目又可能出现依赖冲突,导致编译错误
    3. Go Module:通过go.mod文件管理依赖版本版本,通过go get/go mod指令工具管理依赖包。
      • 依赖管理三要素:
        1. go.mod配置文件,描述依赖
        2. Proxy中心仓库管理依赖库
        3. go get/mod本地工具

三.测试

  • 测试是避免事故发生的一到屏障。
  • 测试分类:回归测试、集成测试、单元测试。成本依次减低,作用越来越大
    1. 单元测试-规则:
      1. 所有测试文件以_test.g结尾
      2. 测试函数:func TestXxx(*testing.T)
      3. 初始化逻辑放到TestMain中
    2. 单元测试-覆盖率:就是代码执行的行数,和简单。 一般覆盖率是50-60%

四.项目

  • 项目内容:展示话题和回帖列表
  • er图:一个topic话题结构体、post回帖结构体
  • 封层结构:三个部分数据层、逻辑层、视图层。
    1. 数据层:底层数据model,用于封装外部数据的增删改查,主要面向service层,并且对service层透明。
    2. 逻辑层:通过数据层返回数据进行打包封装层成entity
    3. 视图层:处理和外部交互逻辑和数据,比如json化数据。