2.GO上手实践

GO上手实践

并发 VS 并行

并发

多线程程序在一个核的CPU上运行

https://i-blog.csdnimg.cn/blog_migrate/f17b63b6ff4abca7c1afe3e4cd5cba5e.png

并行

多线程程序在 多个核的CPU上运行

https://i-blog.csdnimg.cn/blog_migrate/8798ba6c2c06de1e4973d1268a255894.png

go可以充分发挥多核优势,高效运行

Goroutine

https://i-blog.csdnimg.cn/blog_migrate/bc2ece6067261542a9ec6cce1b9d517f.png

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

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

CSP(communicating Swquential Processes)

https://i-blog.csdnimg.cn/blog_migrate/fa69b0810935fae97f5ce6c0cc1d5634.png

GO语言提倡通过

通信共享内存

而不是通过共享内存而实现通信

Channel

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

  • 无缓冲通道 make(chan int)

  • 有缓冲通道 make(chan int,2)

    https://i-blog.csdnimg.cn/blog_migrate/e9ff8408e7344e901a0e245739f183fb.png

eg:
A子协程发送0~9数字
B子协程计算输入数字的平方
主协程输出最后的平方数

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

并发安全 Lock

对变量执行2000次+1操作,5个协程并发执行

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

WaitGroup

计数器
开启协程+1;执行结束-1;主协程阻塞直到计数器为0.

func ManyGowait() {
    var wg sync.WaitGroup
    wg.Add(5)
    for i := 0; i < 5; i++ {
        go func() {
            defer wg.Done()
            hello(j)
        }(i)
    }
    wg.Wait()
}

依赖管理

GOPATH

  • 环境变量$GOPATH
  • 项目代码直接依赖src下的代码
  • go get下载最新版本的包到src目录下

弊端

https://i-blog.csdnimg.cn/blog_migrate/3770a6d911c8eaa192d1600967b1b372.png

场景:A和B依赖于某一package的不同版本。

问题

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

Go Vendor

  • 项目目录下增加 vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor
  • 依赖寻址方式:vendor =>GOPATH

通过每个项目引入一份依赖的副本,解决了多个项目需要同一个 package依赖的冲突问题。

https://i-blog.csdnimg.cn/blog_migrate/3f2ba0cc20f140b975eb37a2e5e34341.png

弊端

https://i-blog.csdnimg.cn/blog_migrate/0bae5539adfcd370038a344da69eb511.png

问题

  • 无法控制依赖的版本。
  • 更新项目又可能出现依赖冲突,导致编译出错。

Go Module

  • 通过go.mod文件管理依赖包版本
  • 通过go get/go mod指令工具管理依赖包

依赖管理三要素

配置文件,描述依赖 go.mod

依赖配置-go.mod

module example/project/app  //依赖管理基本单元
go 1.16//原生库
require (
    //单元依赖
    example/lib1 v1.0.2
    example/lib2 v1.0.0 // indirect
    example/lib3 v0.1.0-20190725025543-5a5fe074e612
    example/lib4 v0.0.0-20180306012644-bacd9c7ef1dd//   indirect
    example/lib5/v3 v3.0.2
    example/lib6 v3.2.0+incompatible
)

依赖标识:[Module Path] [Version/Pseudo-version]

依赖配置-version

语义化版本

  • M A J O R . {MAJOR}. MAJOR.{MINOR].${PATCH}
    eg:V1.3.0 V2.3.0
    基于commit伪版本
  • v×.0.0-yyyymmddhhmmss-abcdefgh1234
    eg:v0.0.0-20220401081311-c38fb59326b7
    v1.0.0-20201130134442-10cb98267c6c

依赖配置- indirect

https://i-blog.csdnimg.cn/blog_migrate/fe399a7752e4215ddfa9ac5cdd9ba1e5.png

https://i-blog.csdnimg.cn/blog_migrate/6ce8d9c85b589d3900e5c9e38134b4ab.png

使用indirect标明间接依赖模块

依赖配置- incompatible

https://i-blog.csdnimg.cn/blog_migrate/1139fc0d07234333711c20ccde78c46c.png

  • 主版本2+模块会在模块路径增加/vN后缀。
  • 对于没有go.mod文件并且主版本2+的依赖,会+incompatible

依赖分发- 回源

https://i-blog.csdnimg.cn/blog_migrate/b26078e2f36df044aaa504faf50dfc2e.png

  • 无法保证构建稳定性增加/修改/删除软件版本
  • 无法保证依赖可用性删除软件
  • 增加第三方压力
    代码托管平台负载问题

中心仓库管理依赖库 Proxy

https://i-blog.csdnimg.cn/blog_migrate/e67bac666e5b44ada497c83a4aea0503.png

依赖分发-变量GOPROXY

GOPROXY="https://proxy1.cn,https://proxy2.cn,direct服务站点URL列表,“direct”表示源站

https://i-blog.csdnimg.cn/blog_migrate/93aa68c97f04fc51f3117c2157fcf2f5.png

本地工具 go get/mod

https://i-blog.csdnimg.cn/blog_migrate/e710d538802b0989faa297d1fc6de733.png

https://i-blog.csdnimg.cn/blog_migrate/455a5a67ea8cdcfe34cde9d6c0ace0c5.png

测试

https://i-blog.csdnimg.cn/blog_migrate/cc3d8d65b8ecb85d1871da7089253f31.png

从上到下,覆盖率逐层变大,成本却逐层降低

单元测试

https://i-blog.csdnimg.cn/blog_migrate/fccc58755cfe3d3dc75e90008e7942ef.png

单元测试-规则

  • 所有测试文件以_test.go结尾

    https://i-blog.csdnimg.cn/blog_migrate/0f9d7b43b49e2db4ab535841fdea5edd.png

  • func TestXxx(*testing.T)

    https://i-blog.csdnimg.cn/blog_migrate/d19626953cff1f6a844e7235c0c4327f.png

  • 初始化逻辑放到TestMain中

eg:
https://i-blog.csdnimg.cn/blog_migrate/670701c2db4f426d857c543815876672.png
https://i-blog.csdnimg.cn/blog_migrate/0cd9404e6b32f9f28feb9074386b16ab.png

单元测试-assert

https://i-blog.csdnimg.cn/blog_migrate/87e407191df5785c90a10c00e90dbac2.png

单元测试-覆盖率

如何衡量代码是否经过了足够的测试?
如何评价项目的测试水准?
如何评估项目是否达到了高水准测试等级?

代码覆盖率

https://i-blog.csdnimg.cn/blog_migrate/b4a2b0855fd01cdec8a39df78a9a2231.png

https://i-blog.csdnimg.cn/blog_migrate/e1b469b4eb01d08eef76fd7e6564f112.png

单元测试-Tips

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

单元测试-依赖

在这里插入图片描述
在这里插入图片描述

单元测试 - Mock

monkey : https://github.com/bouk/monkey

快速Mock函数

  • 为一个函数打桩
  • 为一个方法打桩

在这里插入图片描述
在这里插入图片描述

基准测试

基准测试-例子

在这里插入图片描述

基准测试-运行

在这里插入图片描述

基准测试-优化

在这里插入图片描述

项目实践

需求设计

需求背景

在这里插入图片描述

需求描述

  • 展示话题(标题,文字描述)和回帖列表
  • 暂不考虑前端页面实现,仅仅实现一个本地web
  • 服务话题和回帖数据用文件存储

需求用例

在这里插入图片描述

ER图-Entity Relationship Diagram

在这里插入图片描述

分层结构

在这里插入图片描述

  • 数据层:数据Model,外部数据的增删改查
  • 逻辑层:业务Entity,处理核心业务逻辑输出
  • 视图层:视图view,处理和外部的交互逻辑

组件工具

Repository

结构体

在这里插入图片描述

Repository-index

在这里插入图片描述

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

在这里插入图片描述

Repoditory-查询

在这里插入图片描述

Service

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Controller

在这里插入图片描述

Router

在这里插入图片描述

运行

运行测试
go run server.go

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wooovi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值