Go进阶

75 阅读3分钟

Go进阶 | 青训营笔记

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

文章简介

  • 语言进阶
  • 依赖管理
  • 测试

语言进阶

并发和并行

  • 两个及以上的线程在同一个时间段内运行
  • 两个及以上的线程在同一时刻运行

协程

协程,英文名Coroutine。但在 Go 语言中,协程的英文名是:gorutine。它常常被用于进行多任务,即并发作业。没错,就是多线程作业的那个作业。

协程的特点:

  • 多个协程可由一个或多个线程管理,协程的调度发生在其所在的线程中。
  • 可以被调度,调度策略由应用层代码定义,即可被高度自定义实现。
  • 执行效率高。
  • 占用内存少。

线程和协程的对比:

比较的点线程协程
数据存储内核态的内存空间一般是线程提供的用户态内存空间
切换操作操作最终在内核层完成,应用层需要调用内核层提供的 syscall 底层函数应用层使用代码进行简单的现场保存和恢复即可
任务调度由内核实现,抢占方式,依赖各种锁由用户态的实现的具体调度器进行。例如 go 协程的调度器
语音支持程度绝大部分编程语言部分语言:Lua,Go,Python …
实现规范按照现代操作系统规范实现无统一规范。在应用层由开发者实现,高度自定义,比如只支持单线程的线程。不同的调度策略,等等

协程的使用:

func TestGorutine(t *testing.T) {
		// 控制等待所有协程都执行完再退出程序
    wg := sync.WaitGroup{} 
    wg.Add(2)

    // 运行一个协程
    go func() {
        fmt.Println(1)
        wg.Done()
    }()
    // 运行第二个协程
    go func() {
        fmt.Println(65)
        wg.Done()
    }()
		// 协程没有运行结束则不会停止
    wg.Wait()}

协程之间的通信:

协程之间是通过通信而不是共享内存来实现通信的。

通道:

// 无缓冲通道
make (chan 数据类型)
// 有缓冲通道
make (chan 数据类型, 2)

并发安全lock(相当于Java里面的Lock,需要自己手动释放)

var (
	lock sync.Mutex
)

func test() {
	for i:= 0; i < 200; i++ {
		lock.Lock()
		i += 1
		lock.UnLock()
}

依赖管理

依赖管理的演变路线

GOPATH→Go Vender→Go Module

GOPATH

  • 项目代码直接依赖src下的代码
  • go get下载最新版本的依赖包到src下面

缺点:

  • 无法实现包的多版本控制

Go Vender

  • 项目目录下增加vender文件,所有依赖包副本形式放在vender目录下
  • 依赖寻址的方式:vender→GOPATH

缺点:

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

Go Module

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

测试

单元测试

测试最细小的部分,可用于测试某个功能函数是否会出问题。同时成本最高。

  • 测试规则
  1. 所有的测试文件以_test.go 结尾
  2. 测试函数的命名方式:func TestXxxxx(t * testing.T)
  3. 初始化逻辑放到TestMain中
func TestMain(m *testing.M) {
	// 测试前需要初始化的工作
	code := m.Run()
	// 测试后所需要做的工作
}
  • assert

用于判断测试结果是否与预期值一样

assert.Equal(t, exceptOutput, outPut)
  • 覆盖率

查看本次测试代码运行整段代码的多少行.

在运行代码的后面加上—cover参数就会显示代码覆盖率

一般覆盖率:50%~60%,较高覆盖率80%

  • 单元测试-Mock

Mock测试使得测试程序不在依赖本地文件或者数据库数据

快读Mock函数

// 为一个函数打桩
func Patch(target, replacement interface {}) *PatchGuard {
		t := reflect.ValueOf(target)
		r := reflect.ValueOf(replacement)
		patchValue(t, r)
		return &PatchGuard(t, r)
}

// func Unpatch(target interface{}) bool {
	return unpatchValue(reflect.VAlueOf(target)
}

基准测试

  • 优化代码,需要对当前代码分析
  • 内置的测试框架提供了基准测试能力

参考链接