GO语言进阶| 青训营笔记

41 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

前言

本篇文章主要谈谈上完课后对go语言的进一步的认识

GO进阶知识

GO协程

image.png 协程,可以说是轻量级线程,由于线程栈空间MB级别,内存占用大,创建开销大,上下文切换的开销大,而协程的栈空间KB级别,一个线程可以创建多个协程,线程需要在内核态完成切换,而且协程只需要在用户态完成上下文切换,减少切换时间,并且程序员可以轻松创建协程。

协程通信

不管是线程还是协程都要解决通信问题,go提供了通道Channel进行协程之间数据通信,也可以使用共享内存,对于共享内存需要加锁防止读写数据错误。

  1. Channel通道

    image.png

ch1 := make(chan int)创建无缓冲通道
ch2 := make(chan int, 3)创建有缓冲通道
  • 无缓冲通道是同步通信,数据发送端和数据接收端必须同时在线,如果只有读端,没有写端,那么读端阻塞。如果只有写端,没有读端,那么写端阻塞。
  • 有缓冲通道是异步通信,只有缓冲区满了写段才阻塞,缓冲区空了读端才阻塞,适用于生产者生产数据快而消费者消费数据慢的场景。
  1. 并发安全Lock
package main

import (
   "fmt"
   "sync"
)

var (
   x    int64
   lock sync.Mutex
   wp   sync.WaitGroup
)

func AddWithLock() {
   defer wp.Done()
   for i := 0; i < 2000; i++ {
      lock.Lock()
      x += 1
      lock.Unlock()
   }

}

func AddWithoutLock() {
   defer wp.Done()
   for i := 0; i < 2000; i++ {
      x += 1
   }
}
func main() {
   x = 0
   for i := 0; i < 5; i++ {
      go AddWithLock()
      wp.Add(1)
   }
   wp.Wait()
   fmt.Println("WithoutLock:", x)
   x = 0
   for i := 0; i < 5; i++ {
      go AddWithoutLock()
      wp.Add(1)
   }
   wp.Wait()
   fmt.Println("WithLock:", x)
}

image.png

共享变量的使用前必须要加锁,使用之后解锁才能保障数据安全。

  1. WaitGroup的使用 在上文中已经使用过WaitGroup,主要是用于等待附协程计算任务完成之后主协程继续计算任务,防止因为主协程过早退出而导致其他附协程退出。

依赖管理

image.png

Go依赖管理经历了三次阶段,分别是GOPATH、Go Vendor、Go Module,但前两种依赖管理模式无法有效的解决版本冲突问题,Go Modules 是Go语言官方推出的依赖管理系统,解决了之前依赖管理系统存在的诸如无法依赖同一个库的多个版本等问题,go module从Go 1.11 开始实验性引入,Go 1.16 默认开启。

单元测试

在项目开发尤其是企业级项目开发过程中,单元测试是查找Bug的有效手段,go语言对于测试也有相应的规范。

  • 所有测试文件以_test.go结尾
  • 测试函数形如func TestXxx(*testing.T)
  • 初始化逻辑放在TestMain中

覆盖率

覆盖率是测试测试质量的一个重要指标,表示测试过程中运行代码行数占所有代码的比重,测试越高也表示测试水准越高。

  • 一般覆盖率:50%-60%,较高覆盖率80%+
  • 测试分支相互独立、全面覆盖
  • 测试单元粒度足够小,函数单一职责

单元测试Mock

image.png 单测需要保证稳定性和幂等性,稳定是指相互隔离,能在任何时间,任何环境,运行测试。幂等是指每一次测试运行都应该产生与之前一样的结果,而要实现这一目的就要用到mock机制。