Go语言进阶-工程进阶 | 青训营笔记

42 阅读2分钟

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

本堂课重点

  • go语言高性能的本质
  • go语言的依赖管理:go path=>go vendor=>go module
  • go语言的测试的方案:单元测试、Mock测试、基准测试

Go语言高性能的本质

并发VS并行

image.png 通过相比较,我们可以看到多线程程序在多核的cpu上运行效率更高,没有等待时间,Go可以充分发挥多核优势,高效运行。 利用多核优势,我们可以开启线程,其实例是:

func hello(i int){
  println("hello goroutine : " + fmt.Sprint(i))
}
func HelloGoRoutine({
    for i := 0;i< 5;i+ {
        gofunc(j int){
            hello(j)
        }(i)
    }
    time.sleep(time.Second)
}

go通信方式

image.png 注意:提倡通过通信共享内存而不是通过共享内存而实现通信

Channel

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

  • 无缓冲通道 make(chan 元素类型)
  • 有缓冲通道 make(chan 元素类型,大小) image.png 实现实例:
func. CalSquare() {
    src:=make(chan int)
    dest =make(chan int,3)
    go func(){
        defer close(src)
        for i :=0; i<10; i{
            src- i
        }
    }()
 for i := range dest {
        //复杂操作
        printin(i)
    }
}

共享内存

通过加入锁的方式,以此保证内存的安全性

var (
    x int64
    lock sync. Mutex
}
func addWithLock(){
    for i :=0; i <2000;i+ {
    lock. Lock()
    x += 1
    lock.UnlockO)
    }
}
func addWithoutLock(){
    for i :=0; i < 2000;i++t {
    ×+=1
    }
}

其结果:addWithLock()符合预期结果,addWithoutLock()结果很多变

WaitGroup

WaitGroup是一个封装类,里面为我们准备了对应的函数供我们用在线程中来共享数据

image.png 其实例:

func ManyGoWait(){
    var wg sync.WaitGroup
    wq.Add( delta: 5)
    for i :=0; i<5;i+ {
        go func(i int){
            defer wg. Donehello(j)
        }(i)
    }
    wg.Wait()
}

依赖管理

Go PATH

  • 环境变量 $GOPATH
  • 项目代码直接依赖src目录的代码
  • go get下载的位置也是src

Go PATH弊端

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

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

GO Vendor

  • 项目目录下增加 vendor文件,所有依赖包副本形式放在$ProjectRoot/vendor
  • 依赖寻址方式: vendor =→> GOPATH (先在vendor目录中寻找,找不到依赖再再src中寻找)

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

Go Vendor弊端

image.png

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

Go Module

  • 通过go.mod文件管理依赖包版本
  • 通过go get/go mod指令工具管理依赖包 其依赖的三要素
  • 配置文件,描述依赖 go.mod
  • 中心仓库管理依赖库 Proxy
  • 本地工具 go get/mod

go.mod

image.png

  • indirect 依赖传递
  • incompatible 主版本2+模块会在模块路径增加/vN后缀;对于没有go.mod文件并且主版本2+的依赖,会+incompatible. 注意:go module在选择依赖时会选择最低的兼容版本

依赖分发

项目在寻找依赖的过程实例:

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

go get

image.png

go module

image.png

测试

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

单元测试

目的:测试每一个函数是否能达到预期

image.png 规则:

  • 所有测试文件以_test.go结尾
  • func TestXxx(testing.T)
  • 初始化逻辑放到TestMain中 实例:
func HelloTomO string {
    return"Jerry"
}
func TestHelloTom(t *testing. T) {
    output :=HelloTom()
    expectOutput :="Tom"
    if outputexpectOutput {
        t.Errorf(format:"Expected %s do not match actual%s",expectOutput,output)
    }
}

有一个十分简单的工具可以帮助我们不需要写判断

导入:"github.com/stretchr/testify/assert"

调用:assert. Equal(t,expectOutput,output) 衡量代码能否通过测试——覆盖率 代码覆盖率实例:

func JudgePassLine(score int16) bool i
    if score ≥ 60 {
        return true
    }
    return false
}
func TestJudgePassLineTrue(t *testing. T){
    isPass := JudgePassLine( score: 70)
    assert.Equal(t, expected: true, isPass)
}

MOCK测试

image.png 对ReadFirstLine打桩测试,不在依赖本地文件

基准测试

  • 优化代码,需要对当前代码分析
  • 内置的测试框架提供了基准测试的能力
import(
    "math/rand"
)
var ServerIndex [10]int
func InitServerIndex({
        for i :=0; i<10;i+{
        ServerIndex[i] = i+100
     }
}
func Select(int {
    return ServerIndex[rand. Intn( n:10)]
}

个人总结

经过这一天的学习,我深入了解go语言,知识点很清楚,可是项目那部分跟知识点断层,有点难以理解。