day2_Go语言上手-工程实践|青训营笔记

102 阅读1分钟

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

1.语言进阶--并发编程

Goroutine通过高效的调度模型,实现协程的高并发操作 Channel提倡通过通信实现共享内存 Sync(lock并发安全操作 wiatgroup实现协程间同步)

并发与并行

并发: 多线程程序在一个核的CPU上运行。 单核CPU中,为了实现多个程序同时运行的假象,通常以时间片调度方式,让每个进程每次执行一个时间片,时间片用完就切换下一进程。由于时间片很短,一段时间内就有多个进程执行。

并行: 多线程程序在多个核的CPU上运行 真正的多个程序同时执行,只能在多核CPU上

image.png

image.png

Goroutine 协程:用户态,轻量级线程,栈KB级别 线程:内核态,线程跑多个协程,栈MB级别

package concurrence

import (
   "fmt"
   "time"
)

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)
   }
   //暴力通过sleep加阻塞,保证协程在执行完之前,主线程不退出
   time.Sleep(time.Second)
}
package concurrence

import "testing"

func TestManyGo(t *testing.T) {
      HelloGoRoutine()
}

image.png

协程之间通信

CSP(Communicating Sequential Processes)通信顺序进程,是一种并发编程模型,通过channel共享内存

go也保存着通过共享内存实现通信的机制,对于通过共享内存实现通信,对于多访问需要实现加锁,会影响到程序性能

image.png

channel 是一种引用类型,创建需要通过make关键字 image.png 无缓冲通道(同步通道):使得发送的goroutine和接收的goroutine之间同步化 有缓冲通道(生产消费模型):带有缓冲区,可以解决无缓冲通道的同步问题

src实现了A,B协程间的通信,无缓冲通道,保证了顺序性 desc 使用带缓冲的通道是因为消费者的消费速度较慢(打印),减少由于消费者的消费速度,影响到生产者的执行效率

package concurrence

import "fmt"

func CalSquare() {
   src := make(chan int)
   dest := make(chan int, 3)
   //A子协程发送0~9数字
   //
   go func() {
      defer close(src)
      for i := 0; i < 10; i++ {
         src <- i
      }
   }()
   //B子协程计算输入数字的平方
   go func() {
      defer close(dest)
      for i := range src {
         dest <- i * i
      }
   }()
   //主协程输出最后的平方数
   for i := range dest {
      fmt.Println(i)
   }
}

保留了共享内存实现通信

package concurrence

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)
   x = 0
   for i := 0; i < 5; i++ {
      go addWithLock()
   }
   time.Sleep(time.Second)
   println("WithLock:", x)
}

func ManyGoWait() {
   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()
}

使用优雅的WaitGroup代替Sleep

image.png 计数器:开始协程+1,执行结束-1,主协程阻塞直到计数器为0

2.依赖管理--依赖管理演进路线

Go依赖管理演进路线 Go Module实战

依赖管理三要素 1.配置文件,描述依赖 go.mod 2.中心仓库管理依赖库 Proxy 3.本地工具 go get/mod

image.png GOPATH image.png 弊端 image.png A和B不能同时构建成功

Go Vendor image.png

弊端 image.png

Go Module

image.png

依赖配置 go.mod image.png 依赖配置 version

image.png 版本定义规则 1.语义化版本

MAJOR 可以不兼容 MINOR 通常是增加新功能,需要在MAJOR下保持前后兼容 PATCH 做代码bug的修复

2.基于commit伪版本 版本前缀-时间戳-12位hash校验码

关键字 1.indirect 非直接依赖 image.png

2.incompatible

image.png

依赖图

image.png 答案B 选择最低的兼容版本,保证C1.3和C1.4兼容

依赖分发-回源 表示依赖从哪下载,如何下载 image.png 直接从指定仓库下载存在问题

image.png

出现Proxy,解决上面的问题,实现了稳定可靠的依赖分发 image.png

Proxy配置

direct表示前面的都没有的话,会回源到第三方代码平台 image.png

go mod工具 go get go mod

go get

image.png

go mod

image.png

3.测试--单元测试

单元测试 Mock测试 基准测试

image.png

单元测试组成部分 image.png

编写规则 image.png

image.png

assert

image.png

评估单元测试-代码覆盖率

image.png

image.png

image.png

由于外界依赖可能导致测试不稳定->推出Mock技术

image.png

image.png

image.png

基准测试 对代码性能进行测试

image.png

image.png

4.项目实战--项目需求,需求拆解,逻辑设计,代码实现

项目拆解 代码设计 测试运行 image.png

image.png

image.png

image.png

需求用例

image.png

E-R图 image.png Topic和Post 一对多的关系

分层结构 image.png

组件工具

image.png go get gopkg.in/gin-gonic/gin.v1@v1.3.0

image.png

image.png

image.png

sync.Once 在高并发场景下只执行一次,单例模式 image.png

image.png

image.png

没有前后依赖,可以考虑用并行提高执行效率 image.png

image.png

通过gin搭建整个web框架 image.png

image.png