这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天.
视频首先介绍了三个基础概念,协程高并发,通道概念以及安全锁的概念
go支持比线程更轻量级的协程,语法为go func(),此时主线程会开辟协程,协程独立于主进程的运行,所以会存在主进程运行完而协程还未结束的情况,每次调用go都会开辟一个新协程,所以运行更快。 在go语言中协程会互相通信,通信的介质就是内存。
锁机制需要引入sync包
lock sync.Mutex//保护临界资源,防止多个go协程同时访问一个内存,锁机制有效的保证一次只能有一个go进行访问
func addWithLock() {
for i:=0;i<200;i++{
lock.Lock()
x += 1
lock.Unlock()
}
}
go addWithLock()
锁机制在该代码中能保证x的值不会同时被同时读取,所以x值受到锁机制的保护
随后视频介绍了协程资源释放的例子,需要引入等待同步组sync.WaitGroup,开启多个go协程,当主进程结束后可能协程还未结束,若想保证协程都运行结束后主进程再结束,就需要WaitGroup机制,类似于计数器,当程序开启一个协程后wg.Add(1),等待协程结束后进行释放defer wg.Done()。随后进行等待wg.Wait(),最后所有协程结束后主进程才会退出。
Go依赖问题 go管理依赖三要素,配置文件go.mod,中心仓库管理依赖proxy,本地工具go get/mod。 其中go.mod文件中包含代码所需要的非基本的库,需要从外部获取,利用本地工具进行拉取,依赖可能通过多层中心仓库进行获取,若通过多层中心仓库获取则是indirect。
代码测试问题
项目测试分为三种,回归测试,集成测试,单元测试。回归测试即在客户端运行查看可能存在的bug,单元测试则需要对代码内一个个函数模块进行测试,以防止最大限度的程序问题。 代码,测试规范如下,需要对测试的函数后缀加上_test,在测试函数中前面加上Test,以及参数加上t *testing.T。
在测试中,将需要测试的函数输出值与期望的输出值进行对比,可以查看对比结果,以此来检测代码的故障问题,其中引入assert函数,该函数可以直接调用方法Equal进行对比,同时在测试阶段可以调用 go test XXX.go XXX_test.go --cover的语法查看代码覆盖率,由于输入的值可能不会使整个代码跑完整,在含有if分支时剩余部分可能不会进行测试,所以代码覆盖率越高说明程序健壮性更强。
package Test
import "testing"
import "github.com/stretchr/testify/assert"
func TestHelloTom(t *testing.T) {
output := HelloTom()
expectOutput := "Tom"
/* if output != expectOutput{
t.Errorf("expected %s do not match actual %s",expectOutput,output)
}*/
assert.Equal(t,expectOutput,output)
}
若测试的函数中包含本地文件的输入,由于本地文件可能会被更改,所以测试函数可将函数含风险部分进行替换。利用Mock进行替换,需要引入bou.ke/monkey包
package Test
import "strings"
//打桩测试,当对外部文件需要进行测试时,外部文件可能会对值进行替换
//所以打桩测试将一个测试函数替换原函数,最终使得原函数无论是否被恶意更改都不影响测试函数。利用MOCK打桩
func FileReplace() string {//利用函数代替外部读入,因为该函数会被替换所以不影响
//println("hello school")
return "line110111"
}
func ProcessFirstLine() string {
line := FileReplace()
destLine := strings.ReplaceAll(line,"11","00")
return destLine
}
package Test
import (
"github.com/stretchr/testify/assert"
"testing"
"bou.ke/monkey"
)
func TestProcessFirstLineMock(t *testing.T) {
monkey.Patch(FileReplace, func()string {
return "line110"
})
defer monkey.Unpatch(FileReplace)
line:=ProcessFirstLine()
assert.Equal(t, "line000",line)
}
该程序中利用 func()string { return "line110" }匿名函数替换FileReplace函数,所以返回结果是line110代替line110111进行输入,所以无论FileReplace函数的结果传回任意值都会被匿名函数所替换monkey.Patch(a,b)其中b作为a的代替函数,a为原函数,最后匹配不影响ProcessFirstLine()函数内的其他不确定函数的干扰,当文件函数被更改不影响ProcessFirstLine()函数的正确性。
最后老师讲了工程代码设计思路以及实现。对目前而言还有一定的难度,需要继续提升。 上课收获很大,老师讲的内容需要下来仔细练习并且反复观看,有时候第一遍可能不能理解的部分,当自己手敲过后也许能有更深的体会。